evnbr / bindery Goto Github PK
View Code? Open in Web Editor NEWBook layout in the browser
Home Page: https://bindery.info
License: MIT License
Book layout in the browser
Home Page: https://bindery.info
License: MIT License
For certain posts, I display a hero image before the post header (i.e., post title + metadata). I am trying to force the hero image to always appear on the left page, with the post header always appearing to the right of that. There should be no other content on these facing pages (text should flow to the next left facing page after the post header).
I have a set of PageBreak rules as follows:
Bindery.PageBreak({ selector: ".hero-figure", position: "before", continue: "left" }), // force .hero-figure to be on left facing pages
Bindery.PageBreak({ selector: ".post-header", position: "before", continue: "right" }), // force .post-header to be on right facing pages
Bindery.PageBreak({ selector: ".post-header", position: "after", continue: "left" }), // flow content after .post-header onto next page
Unfortunately, I end up with a variety of odd results:
Sometimes it works:
But this happens a lot:
Any idea what's causing this? Am I misinterpreting how the PageBreak rule works?
Sometimes Bindery doesn't flow content properly and you'll see content overflowing (vertically) on most pages. I've only seen it happen on initial load, but it happens somewhat frequently. If you refresh, things seem to render as expected. Maybe it's due to images not being fully loaded when the script is run?
From #19
if { bleed: true}, 100% is the full height with bleeds. and when { bleed: false }, 100% is just the height of the content area (within the margin).
from #24
just a quick patch ...
// based on node_modules/bindery/dist/bindery.umd.js
class Viewer {
// ...
setLayout(newVal) { // actions.setLayout
if (newVal === this.sheetLayout)
return;
this.sheetLayout = newVal;
// milahu was here
// copy-paste from setSheetSize(newVal)
var sheetSizeChanged = false;
if (newVal == SheetLayout.PAGES && this.pageSetup.paper != SheetSize.A5_PORTRAIT) {
this.pageSetup.paper = SheetSize.A5_PORTRAIT;
sheetSizeChanged = true;
}
else if ((newVal == SheetLayout.SPREADS || newVal == SheetLayout.BOOKLET) && this.pageSetup.paper != SheetSize.A4_LANDSCAPE) {
this.pageSetup.paper = SheetSize.A4_LANDSCAPE;
sheetSizeChanged = true;
}
this.pageSetup.printTwoUp = this.isTwoUp;
this.pageSetup.updateStyleVars();
this.mode = ViewerMode.PRINT;
this.render();
// milahu was here
// copy-paste from setSheetSize(newVal)
if (sheetSizeChanged) {
this.scaleToFit();
setTimeout(() => {
this.scaleToFit();
}, 300);
}
}
my config: A5 pages on A4 paper
SheetLayout.PAGES
is needed to print a "linear" pdf = 1 page per sheet
function binderyOptions(Bindery) {
return {
printSetup: {
// https://bindery.info/docs/#printsetup
/*
// booklet
layout: Bindery.Layout.BOOKLET,
paper: Bindery.Paper.A4_LANDSCAPE,
*/
// no booklet
layout: Bindery.Layout.PAGES, // One page per sheet
paper: Bindery.Paper.A5_PORTRAIT,
marks: Bindery.Marks.NONE, // NONE CROP BLEED BOTH
//bleed: '0pt',
bleed: '-12pt', // workaround: bleed is biased by +12pt -> padding-top: calc(var(--bindery-bleed) + 12pt);
},
pageSetup: {
size: { width: '148mm', height: '209mm' }, // A5. height -1mm to avoid pagebreak https://github.com/evnbr/bindery/issues/109
margin: { top: '10mm', inner: '20mm', outer: '10mm', bottom: '10mm' },
},
view: Bindery.View.PREVIEW, // aka "grid"
};
}
Bindery.makeBook(binderyOptions(Bindery))
to make this work, i also added a5 paper size
SheetSize["A4_LANDSCAPE"] = "a4-landscape";
// add
SheetSize["A5_PORTRAIT"] = "a5-portrait";
SheetSize["A5_LANDSCAPE"] = "a5-landscape";
// ...
case SheetSize.A4_LANDSCAPE:
return { width: a4.height, height: a4.width };
// add
case SheetSize.A5_PORTRAIT:
return a5;
case SheetSize.A5_LANDSCAPE:
return { width: a5.height, height: a5.width };
// ...
const a4 = Object.freeze({ width: '210mm', height: '297mm' });
// add
const a5 = Object.freeze({ width: '148mm', height: '210mm' });
// TODO 210mm or 209mm? maybe need 209mm to avoid extra pagebreaks
Context: I use Bindery with the headless puppeteer.
If I click on "Print" in a browser, I can see the full PDF, perfectly printed.
If I trigger the .pdf
API from puppeteer, I can see white borders.
I tried to add:
.π-zoom-content {
background: yellow;
}
.π-print-sheet {
background: red;
}
.π-spread-wrapper {
background: blue;
}
And narrowed down that the issue starts in .spread-wrapper
.
I tried to add a width: 100% !important
to .π-spread-wrapper
and things seem to be better. But still not ok.
We've tried to fix this for a long time. However, we were not able to do so.
I understand that this is not a bug with Bindery.js (we're pretty sure that it might be puppeteer), but I was wondering if there any suggestion or any feedback on what we could do to make it work.
the fact that the same chromium instance can generate a valid PDF (in non-headless mode) and a PDF with border (headless) suggests that the issue might be in the "export to PDF" function. However, what CSS property that causes such discrepancy is a bit of a mystery.
Anything that we should try next? Have you seen anything like that?
Happy to close the ticket if not relevant.
Thanks.
If a grid of items (e.g., 2-column flexbox div) is continued onto a new page, only the first item of the grid has its top margin removed.
Perhaps check if the continued element has a top-margin and if so get that value and use it to position the entire page negatively from the top?
I'm trying to number figures [1,2,3,...] that resets each chapter, but can't use counter-reset
properly with Bindery because each page is its own context.
Counter-increment in CSS 2.1 requires that its counter be within the scope of the counter-reset, otherwise "implementations should behave as though a 'counter-reset' had reset the counter to 0"
Do you have any ideas on how to accomplish this with Bindery?
Hello Evan,
Above all thank you for the hard work you did here. I discovered Bindery a year ago, I used it in several editorial projects and I love it !
I tried to figure out how to get feedback from Bindery while book is binding, I want to display realtime building pages on a "onload" page. Like you did for HTMLOutput Risd fall 2014 where there is a "building 'n' page". I checked out the code of some projects where there is it but I don't success yet, could you help ?
Thanks a lot.
Desktop:
I'd like to have some full page figures rotated. At first I tried doing this purely through CSS, but it looks like it'll take some JS to work properly.
The CSS I tried:
.hero-figure {
width: 100%;
height: 100%;
margin: 0;
transform: rotate(90deg) translate(0, -100%);
transform-origin: top left;
}
Results in:
As you can see, the width and height of the figure are effectively swapped from the transform; the width of the figure is the height of the page, and the height of the figure is width of the page.
Hey - firstly thanks so much for bindery!
I am trying to convert a series of HTML posts (authored in markdown) into a bindery PDF book.
Example post: https://tomcritchlow.com/2019/11/18/yes-and/
Markdown puts the footnotes at the bottom of the doc. Something like this:
In-line:
<p>I recently read the book <a href="https://www.amazon.com/Impro-Improvisation-Theatre-Keith-Johnstone/dp/0878301178">Impro - Improvisation and the Theatre</a> by Keith Johnstone<sup id="fnref:vgr" role="doc-noteref"><a href="#fn:vgr" class="footnote">1</a></sup>. Itβs a delightful book all about improvisational theatre and importantly <em>how to teach</em> improvisational theatre.</p>
At the bottom of the post:
<div class="footnotes" role="doc-endnotes">
<ol>
Β <li id="fn:vgr" role="doc-endnote">
Β <p>I loved the book and as Venkatesh said <em>βit is a textbook that teaches you how to see the world differently.β</em> so consider it recommended. <img src="/images/Impro-by-Keith-Johnstone.jpg" alt="" />Β <a href="#fnref:vgr" class="reversefootnote" role="doc-backlink">↩</a></p>
Β </li>
Β <li id="fn:unfair" role="doc-endnote">
Β <p>Yes actually internal company politics and performance <em>are</em> unfair but changing that is not the scope of this postβ¦Β <a href="#fnref:unfair" class="reversefootnote" role="doc-backlink">↩</a></p>
Β </li>
Β <li id="fn:arendt" role="doc-endnote">
Β <p>Handily Venkatesh has a <a href="https://www.ribbonfarm.com/2016/12/21/the-computational-condition/">more formal summary of Hannah Arendtβs work here</a> - the first 22 slides are most of what you need for this post.Β <a href="#fnref:arendt" class="reversefootnote" role="doc-backlink">↩</a></p>
Β </li>
Β <li id="fn:speech" role="doc-endnote">
Β <p>Iβve not delved into it but I think there are insights to be had from studying <a href="https://archive.org/details/HowToDoThingsWithWordsAUSTIN">speech act theory</a> here.Β <a href="#fnref:speech" class="reversefootnote" role="doc-backlink">↩</a></p>
Β </li>
Β <li id="fn:sparring" role="doc-endnote">
Β <p><a href="https://tomcritchlow.com/2020/05/28/sparring-and-tenure/">More on sparring here</a>Β <a href="#fnref:sparring" class="reversefootnote" role="doc-backlink">↩</a></p>
Β </li>
Β </ol>
Β </div>
How do I convert these into bindery footnotes? And can I combine these with auto-generated ahref footnotes?
Thanks!
just increments forever
First of all, thank you for this amazing library. Seriously, well done π©
I'm looking for a way to customize where the page count starts on the running header (or somehow offsetting it). In our designs, the cover, title page, table of contents should not count towards page numbers. The problem is that a table of contents can be variable page length, so offsetting the count manually probably wouldn't work.
Can you think of any way of approaching this problem?
Bindery breaks if multiple instance of FullBleedPage and PageBreak are applied to the same element. There are 3 stages to fixing this:
And make it optional?
This bug seems like it's been introduced in dc76ef2: the list-style
should only be set to none
for li.continuation:first-child
β not, as it's currently implemented, for any element matching .continuation
, which happens to include the ul
or ol
that's been continued from the previous page.
Describe the bug
eachPage
gets called multiple times for some pages
To Reproduce
const rule = Bindery.createRule({
eachPage: (page, book) => {
console.log(page.number);
}
});
output:
1
3
4
1
2
3
4
5
Expected behavior
function should only be called once per page
Desktop (please complete the following information):
It would be really awesome to have a keep rule that takes an array of selectors and tries to keep them together. For example: given [h1, p]
if a break would normally occur after h1
, bindery should try to avoid that break if the following element is p
, and instead put the break before the h1
element.
ie in FullBleedPage
With pagebreak rules set and a fullpage set, the flow appears erratic.
Bindery.PageBreak({ selector: ".hero-figure", position: "both", continue: "both" }),
Bindery.PageBreak({ selector: ".post-header", position: "both", continue: "both" }),
with Bindery.FullPage({ selector: ".hero-figure" }),
results in:
The purple image is from the previous post, the "1-inch Buttons" is part of .post-header and the image on the right is a .hero-figure.
Hi !
Thanks for Bindery, it's a perfect script for html book layouting !
I was nevertheless concerned with hyphenations. I'm using chromium to render the book (sometimes it's a bit buggy in firefox), but the css hyphenation rules are not working on chromium + linux.
Is there a way I could hyphenize my text, maybe through something like Hyphenator.js ?
Is there a way to do some text processing while the book is being generated ?
Thanks in advance !
Describe the solution you'd like
So basically I'm using Bindery for something a little different than actually generating a PDF book. I'm mainly using the Flipbook part for this current project I'm working on which an in-game tattoo shop in Grand Theft Auto. Basically u walk up to a book in-game and it then opens up a web interface showing the book, where you can then flip through the pages and its all setup in Vue, and the pages are created dynamically
Describe alternatives you've considered
I have been just adding visibility hidden to the CSS class. Took longer than I expected, since I for some reason failed to spot the emojis in the class names, gave me a good laugh when I realized.
Additional context
It would be really cool, if there was a way to run Bindery in like a Flipbook only mode, I'm thinking that could be handy for people that don't need the other functionality.
[ Placeholder ]
When I use the following code (taken from your example in the docs) to create an index, it is matching the words in the index itself. I have the index at the end of the book. Does that make a difference?
Bindery.PageReference({
selector: ".index-section li",
createTest: (el) => {
const searchTerm = el.textContent.toLowerCase().trim();
return (pageEl) => {
const textToSearch = pageEl.textContent.toLowerCase();
return textToSearch.includes(searchTerm);
}
},
})
bindery 2.3.6 works for all paper formats, except A4 landscape
with A4 landscape, printing creates blank pages for every second page
Reproduce
const binderyOptions = {
paper: Bindery.Paper.A4_LANDSCAPE,
};
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body.js-enabled hr {
height: 0;
border: none;
}
* {
outline: solid 1px red;
}
</style>
<!--
<script src="./bindery.min.js"></script>
-->
<script src="./node_modules/bindery/dist/bindery.umd.js"></script>
<script>
const binderyOptions = {
content: '#content',
rules: [
Bindery.PageBreak({ selector: 'hr', position: 'after' }),
],
printSetup: {
layout: Bindery.Layout.BOOKLET, // A4 = 2 x A5
paper: Bindery.Paper.A4_LANDSCAPE,
marks: Bindery.Marks.NONE, // NONE CROP BLEED BOTH
bleed: '0pt',
},
pageSetup: {
size: { width: '148mm', height: '210mm' }, // A5 = A4 / 2 -> use full page, no cropping
margin: { top: '0mm', inner: '0mm', outer: '0mm', bottom: '0mm' },
//margin: { top: '10mm', inner: '10mm', outer: '10mm', bottom: '10mm' },
},
view: Bindery.View.PREVIEW, // aka "grid"
};
</script>
</head>
<body>
<script>document.body.classList.add('js-enabled')</script>
<div id="content">
<!-- page 1 -->
<h1>title title title title</h1>
<h2>subtitle subtitle subtitle subtitle subtitle subtitle</h2>
<hr>
<!-- page 2 -->
<h3>intro</h3>
<p>
intro intro intro intro intro intro intro intro intro intro intro
</p>
<p>
intro intro intro intro intro intro intro intro intro intro intro
</p>
<hr>
<!-- page 3 -->
<h3>background</h3>
<p>
background background background background background background
</p>
<p>
background background background background background background
</p>
<hr>
<!-- page 4 -->
<h3>method</h3>
<p>
method method method method method method method method method
</p>
<p>
method method method method method method method method method
</p>
</div><!-- end #content -->
<script>Bindery.makeBook(binderyOptions)</script>
</body>
</html>
browser: chrome, firefox
the bug is correlated with the css variable --bindery-page-height
when i remove it from :root { ... }
then it works
no. this only fixes the "emulate css media type: print"
print dialog with css * { outline: solid 1px red; }
outline does not increase size, so there should be no overflow
Is it possible to have the print preview view first when loading the page (1 page / sheet) ?
Apply a class to a page that contains an element.
Would resolve #16
There's not a clear web equivalent of an index to translate.
Real book indexes can get pretty sophisticated.
// nested topics:
Rhode Island School of Design: 4-12
department of graphic design: 4
presidency of John Maeda: 6
bicycle drawings: 7
// ranges
Rhode Island School of Design: 7, 12, 34-55, 72)
// custom alphabetization
Caserta, John: 7
greed, economic: 5
// see also
neoliberalism: 5-7
See also 'chicago school'
Example:
<p>
In 1969, the French curator Yolande Amic
posed this very question to designer
<mark data-index='Eames, Charles'>Charles Eames</mark>.
</p>
Example:
Bindery.Index({ topics: [
{ label: 'Eames, Charles', match: ['Charles Eames', 'Charles and Ray Eames' ] },
{ label: 'America, Unites States of', match: ['USA', 'United States', 'America' ] },
{ label: 'RISD', match: ['Rhode Island School of Design', 'RISD' ] },
] });
I'm trying to use the FullPage rule to display an image that has 100% width and height of the containing page, but it seems like the container has no set height. Do you have an example of how to use this rule to create a full image bleed page?
This is not a bug or a feature request, but rather a request for clarification.
Consider the following content:
The content overflows.
I'd like the red block to be always placed on a new page and I'd like to remove it from the natural flow of the document, like this:
I tried using FullPageBleed, but that does work. If I use the PageBreak, this is what I obtain:
Is there any way I could code a rule to reflow the content as per scenario 3?
Hello! Really enjoy the concept of this library. I can't quite seem to get this functionality working, there's not much documentation on createRules so I'm not sure if I'm doing something incorrectly.
Describe the bug
Following the example here, I attempted to make my own custom ruleset to modify the background of the title page to a gradient. However I can't seem to get it to work.
To Reproduce
Here is my js file at the moment:
`let breakRule = Bindery.PageBreak({
selector: '.page',
position: 'before',
});
let fullBleedRule = Bindery.FullBleedPage({
selector: '.big-figure',
continue: 'same',
});
let spreadRule = Bindery.FullBleedSpread({
selector: '.full-spread',
});
let pageBackgroundRules = Bindery.createRule({
eachPage: function(page, book) {
if(page.number === 1) {
page.background.style.backgroundColor = "linear-gradient(to bottom, #6A82FB, #FC5C7D)";
}
}
});
Bindery.makeBook({
content: {
selector: '#content',
url: 'book_content.html',
rules: [ breakRule, spreadRule, fullBleedRule, pageBackgroundRules ],
}
});`
Expected behavior
For background to be modified. I also tried directly copying and pasting the original rainbowRules example and that also did not work.
Desktop (please complete the following information):
Add the following CSS so that we can do alignment inside pages.
.π-content,
.π-continuation,
.π-continues {
height: 100%;
}
Then we can do things like this:
.credits-page {
display: flex;
flex-direction: column;
justify-content: flex-end;
height: 100%;
}
which will align text to the bottom of a page.
I tried adding the π CSS classes myself, but bindery threw a bunch of errors.
Reported by @jcaserta
π
It's unclear what happens when multiple an element is replace multiple times.
If makeBook
is called inline before the selected element is loaded, error message says it doesn't exist.
(Check if document.readyState == 'loading'
and if so, listen for change
https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState)
The documentation states the following:
"Keep in mind you can also use multiple RunningHeaders to create multiple elementsβ for example, to add both a page number at the bottom and a chapter title at the top."
Is there an example on how to do this? By only using RunningHeader two times, it will still displayed at the top of the page. How is it possible to set it to the top and to the bottom of the page?
Hi,
I noticed that when trying to print with crop marks, the print area's left edge gets aligned with the page's left edge and the left horizontal crop marks are inexistent.
I'm guessing this is by design but was wondering whether there could be a way to have the print area centred inside the page?
If footnotes are applied to a link in a header, the RunningHeader will display the superscript number. e.g., <h1><a href="">Title</a></h1>
will show as "Title1" in the running header given the following:
Bindery.Footnote({
selector: "a",
render: (el, number) => `<span class="footnote"><sup>${ number }</sup><a href="${ el.href }">${ el.href }</a></span>`,
}),
Bindery.RunningHeader({
render: (page) => {
if (page.isEmpty) return "";
else if (page.element.querySelector("h1")) return "";
else if (page.isLeft) return `<div class="running-header"><span class="page-number">${ page.number }</span> ${ page.heading.h1 }</div>`;
},
}),
Bravo for the evolutions and in particular the possibility to open on a view "print" directly. Is there a solution to not display all controls, just the "print" button and change the label of this button by "print or save pdf" for example. Overall, it would be nice to be able to set the controls that are displayed.
I need to customize the interface a bit, so I removed the control display and added a "print or save pdf" button that starts printing correctly, but it appears on the printed document. How to add elements (texts or others) without being printed? I tried with @media print without success.
Hi Evan,
We finally published the book! https://learnk8s.io/first-steps
You can see bindery in action here: https://learnk8s.io/a/in-depth-hands-on-kubernetes-online-courses/first-steps-preview.v1.pdf
There are a few amendments needed, but Bindery allowed us to do much more tricks than any other tool we've tried.
I wanted to thank you for 1) creating the library 2) answering questions and accepting PRs.
If you ever want to learn Kubernetes, please drop me an email at daniele at learnk8s dot io. I'll make sure you will have full access to our content.
Thanks again,
Dan
First of all, a big bravo for the work done.
Easy to use and yet powerful.
But sometimes I have a problem with my paragraphs: they don't always split. See the following example, and the associated code.
const {makeBook, PageBreak, RunningHeader, Layout, Paper, Marks, Split} = Bindery;
makeBook({
content: '#content',
printSetup: {
layout: Layout.PAGES,
paper: Paper.AUTO,
marks: Marks.NONE
},
pageSetup: {
size: { width: '148mm', height: '209.5mm' },
margin: {
top: '0.4in',
bottom: '0.3in',
inner: '0.3in',
outer: '0.3in',
},
},
rules: [
Split({
selector: 'p',
toNext: 'continues',
fromPrevious: 'continued',
}),
PageBreak({
selector: 'section',
position: 'before',
continue: 'right'
}),
RunningHeader({
render: (page) => {
if (page.isEmpty || page.number <= 1) return '';
if (page.isLeft) return `${page.number} Β· Borden `;
else if (page.isRight) {
let section = page.heading.h1 || '';
if (section !== '') return `${section} Β· ${page.number}`;
else return `${page.number}`;
}
},
}),
]
});
The original document is hidden on the page.
When the content is formatted, it is cloned. Unfortunately, all IDs are cloned too.
This breaks the anchors in the document (particularly when using a Table of Contents).
hi - really grateful for this project. thanks for your time and energy.
i wanted to ask if bindery was keyboard accessible? specifically if the page turning was attached to any keyboard events. i'd like my bindery project to be navigable by folx with disabilities. here is a related page from the world wide web consortium:
Are there any strategies or suggestions for setting a back page cover (or the left side of the first spread)?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.