nehan-player
Version:
web component for paged media powered by nehan layout engine
328 lines • 9.48 kB
JavaScript
import { PhysicalSize } from 'nehan';
const svgLeft = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M9.78 12.78a.75.75 0 01-1.06 0L4.47 8.53a.75.75 0 010-1.06l4.25-4.25a.75.75 0 011.06 1.06L6.06 8l3.72 3.72a.75.75 0 010 1.06z"></path></svg>`;
const svgRight = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.22 3.22a.75.75 0 011.06 0l4.25 4.25a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06-1.06L9.94 8 6.22 4.28a.75.75 0 010-1.06z"></path></svg>`;
;
export const layoutSettings = {
defaultLayout: "1x1",
pageGapSize: 32,
minFontSize: 10,
maxFontSize: 48,
minWidth: 300,
minHeight: 300,
minMultiColWidth: 600,
minMultiRowHeight: 500,
maxBorderSize: 20,
elementPaddingTop: 48,
};
export function getScreenPageCount(layout) {
switch (layout) {
case "1x1": return 1;
case "1x2":
case "2x1": return 2;
case "2x2": return 4;
}
}
export function getPageOrder(layout, writingMode) {
const isRTL = writingMode.isVerticalRl();
switch (layout) {
case "1x1": return [1];
case "1x2": return isRTL ? [3, 1] : [1, 3];
case "2x1": return [1, 2];
case "2x2": return isRTL ? [3, 4, 1, 2] : [1, 2, 3, 4];
}
}
export function isMultiCol(layout) {
return layout === "1x2" || layout === "2x2";
}
export function isMultiRow(layout) {
return layout === "2x1" || layout === "2x2";
}
export function decGridCol(layout) {
if (layout === "1x2") {
return "1x1";
}
if (layout === "2x2") {
return "2x1";
}
return layout;
}
export function decGridRow(layout) {
if (layout === "2x1") {
return "1x1";
}
if (layout === "2x2") {
return "1x2";
}
return layout;
}
export function getElementLrPaddingSize(writingMode, layout, elementSize, fontSize, lineHeight, borderSize) {
if (writingMode.isTextHorizontal()) {
return fontSize;
}
const lhp = fontSize * lineHeight;
const minSpace = 2 * fontSize;
let availableWidth = elementSize.width - minSpace - 2 * borderSize;
if (isMultiCol(layout)) {
availableWidth -= layoutSettings.pageGapSize + 1;
}
const lineCount = Math.floor(availableWidth / lhp);
const halfSurplusSize = Math.floor((availableWidth - lhp * lineCount) / 2);
return fontSize + halfSurplusSize;
}
export function getElementBottomPaddingSize(writingMode, layout, elementSize, fontSize, lineHeight, borderSize) {
return fontSize * 1.5;
}
export function getPlayerSize(elementSize, fontSize, lrPadding, bottomPadding, borderSize) {
return new PhysicalSize({
width: elementSize.width - lrPadding * 2 - borderSize * 2,
height: elementSize.height - layoutSettings.elementPaddingTop - bottomPadding,
});
}
export function getPageSize(layout, playerSize) {
switch (layout) {
case "1x1": return new PhysicalSize({
width: playerSize.width,
height: playerSize.height,
});
case "1x2": return new PhysicalSize({
width: (playerSize.width - layoutSettings.pageGapSize - 1) / 2,
height: playerSize.height,
});
case "2x1": return new PhysicalSize({
width: playerSize.width,
height: (playerSize.height - layoutSettings.pageGapSize - 1) / 2,
});
case "2x2": return new PhysicalSize({
width: (playerSize.width - layoutSettings.pageGapSize - 1) / 2,
height: (playerSize.height - layoutSettings.pageGapSize - 1) / 2,
});
}
}
export function getPlayerHTML() {
return `
<div class="player">
<div class="screen-wrap">
<div id="screen-header">
<span id="title"><slot name="title"></slot></span>
<span id="sub-title"><slot name="sub-title"></slot></span>
</div>
<div id="screen">
<div class="page" id="page-1"></div>
<div class="hline" id="hline-12"></div>
<div class="page" id="page-2"></div>
<div class="vline"></div>
<div class="page" id="page-3"></div>
<div class="hline" id="hline-34"></div>
<div class="page" id="page-4"></div>
</div>
<div id="screen-footer">
<div class="nombre">
<span id="page-no"></span>
<span id="separator">/</span>
<span id="page-count"></span>
</div>
</div>
</div>
<menu id="menu">
<button class="pager" id="goto-left">
<slot name="goto-left-label">
${svgLeft}
</slot>
</button>
<button class="pager" id="goto-right">
<slot name="goto-right-label">
${svgRight}
</slot>
</button>
</menu>
<div id="slider">
<input id="slider-range" type="range" min="1" max="1" step="1" value="0">
</div>
<footer id="footer"><slot name="footer"></slot></footer>
<div id="direct-content"><slot name="content"></slot></div>
</div>`;
}
export function getPlayerStyle(writingMode, playerSize, fontSize, lrPadding, bottomPadding, borderSize) {
const direction = writingMode.isVerticalRl() ? "rtl" : "ltr";
return `
.player {
margin-bottom: 2em;
overflow: hidden;
}
.screen-wrap {
background: wheat;
border-width: ${borderSize}px ${borderSize}px 0 ${borderSize}px;
}
position: relative;
font-size: 12px;
top: 32px;
left: 32px;
width: ${playerSize.width}px;
white-space: nowrap;
}
color: rgba(80,80,80, 0.8);
}
color: rgba(80,80,80, 0.8);
}
width: ${playerSize.width}px;
height: ${playerSize.height}px;
padding: ${layoutSettings.elementPaddingTop}px ${lrPadding}px ${bottomPadding}px;
}
padding-bottom: ${layoutSettings.pageGapSize / 2}px;
}
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-top: 0;
width: ${playerSize.width}px;
color: white;
font-size: 14px;
background:
padding: 10px ${lrPadding}px;
border-width: 0 ${borderSize}px ${borderSize}px ${borderSize}px;
}
margin-top: 10px;
visibility: hidden; /* hide until onCompletePage is called. */
width: ${playerSize.width}px;
padding: 0 ${lrPadding}px;
}
width: ${playerSize.width}px;
}
width: ${playerSize.width}px;
padding: 0 32px;
text-align: right;
font-size: 0.82em;
}
visibility: hidden;
}
input[type="range"] {
direction: ${direction};
}
.nehan-line a {
color:
}
.pager {
flex-basis: 100px;
padding: 4px 0px;
}
.nombre {
font-size: 0.92em;
text-align: center;
flex-basis: 150px;
}
.vline {
border-left: 1px dotted
}
.hline {
border-bottom: 1px dotted
}
`;
}
export function getGridStyle(layout, playerSize) {
const pageSize = getPageSize(layout, playerSize);
switch (layout) {
case "1x1":
return `
display:none;
}
`;
case "1x2":
return `
display: grid;
grid-template-rows: 100%;
grid-template-columns: ${pageSize.width}px 1px ${pageSize.width}px;
gap: 0 ${layoutSettings.pageGapSize / 2}px; /* vline makes 2*gapSize, so we use half for colGap. */
}
grid-row: 1/2;
grid-column: 1/2;
}
.vline {
grid-row: 1/3;
grid-column: 2/3;
}
grid-row: 1/2;
grid-column: 3/4;
}
display: none;
}
`;
case "2x1":
return `
display: grid;
grid-template-rows: ${pageSize.height}px 1px ${pageSize.height}px;
grid-template-columns: 100%;
gap: ${layoutSettings.pageGapSize / 2}px 0px; /* hline makes 2*gapSize, so we use halt for rowGap. */
}
grid-row: 1/2;
grid-column: 1/2;
}
grid-row: 2/3;
grid-column: 1/2;
}
grid-row: 3/4;
grid-column: 1/2;
}
display: none;
}
`;
case "2x2":
return `
display: grid;
grid-template-rows: ${pageSize.height}px 1px ${pageSize.height}px;
grid-template-columns: ${pageSize.width}px 1px ${pageSize.width}px;
gap: ${layoutSettings.pageGapSize / 2}px; /* vline and hline make 2*gapSize so we use half gap size */
}
grid-row: 1/2;
grid-column: 1/2;
}
grid-row: 2/3;
grid-column: 1/2;
}
grid-row: 3/4;
grid-column: 1/2;
}
.vline {
grid-row: 1/4;
grid-column: 2/3;
}
grid-row: 1/2;
grid-column: 3/4;
}
grid-row: 2/3;
grid-column: 3/4;
}
grid-row: 3/4;
grid-column: 3/4;
}
`;
}
}
//# sourceMappingURL=PlayerLayout.js.map