--- /dev/null
+<?php
+
+namespace Fluidbook\Tools\Compiler;
+
+use Cubist\Util\CommandLine;
+use Cubist\Util\Graphics\Color;
+
+trait Styles
+{
+ protected $lessVariables = [];
+
+ protected function writeCSS($links)
+ {
+ $res = array();
+
+ $this->addFontKit('OpenSans');
+
+ $lessContents = '';
+
+ $this->lessVariables['font'] = $this->_font($this->config->interfaceFont);
+ $this->lessVariables['text-transform'] = $this->_themeBoolean($this->config->interfaceFontUppercase) ? 'uppercase' : 'inherit';
+
+ $this->lessVariables['css-scale'] = $this->cssScale;
+
+ $this->lessVariables['slider-background'] = Color::colorToCSS(!$this->config->sliderBackground ? 'rgba(0,0,0,0.1)' : $this->config->sliderBackground);
+ $this->lessVariables['slider-handle'] = Color::colorToCSS(!$this->config->sliderHandle ? '#ffffff' : $this->config->sliderHandle);
+ $this->lessVariables['slider-display'] = $this->_lessBoolean($this->config->pagesBar);
+ $this->lessVariables['slider-thumb-background'] = Color::colorToCSS($this->config->pageBarThumbBack);
+ $this->lessVariables['pages-background'] = $this->config->forceWhiteBackground ? '#ffffff' : 'transparent';
+
+
+ // General theme
+ $cssWidth = $this->cssWidth;
+ $cssHeight = $this->cssHeight;
+ $cssScale = $this->cssScale;
+ $w2 = ($cssWidth * 2) . 'px';
+ $h = $cssHeight . 'px';
+
+ $wm = ($this->getWidth() * $this->multiply) . 'px';
+ $hm = ($this->getHeight() * $this->multiply) . 'px';
+ $w = $cssWidth . 'px';
+ $offsetLeft = round(($this->optimalWidth - $cssWidth) / 2, 3);
+ $offsetLeft2 = $offsetLeft * 2;
+ $offsetTop = round(($this->optimalHeight - $cssHeight) / 2, 3);
+ $navTop = ($cssHeight - 40 - 100) / 2;
+ $leftOfRightPage = (floor($cssWidth) - 1) . 'px';
+
+ $this->lessVariables['z'] = $this->z;
+ $this->lessVariables['book-page-width'] = $w;
+
+ if ($this->config->correctCenter && !$this->isMobileFirst()) {
+ $this->lessVariables['book-page-correct-width'] = ceil($w) + 1;
+ $this->lessVariables['book-page-correct-height'] = ceil($h) + 1;
+ } else {
+ $this->lessVariables['book-page-correct-width'] = $w;
+ $this->lessVariables['book-page-correct-height'] = $h;
+ }
+
+
+ $this->lessVariables['book-page-height'] = $h;
+ $this->lessVariables['book-page-ratio'] = floatval($w) / floatval($h);
+
+ $this->lessVariables['page-shade-opacity'] = min(1, $this->config->shadeAlpha / 50);
+ $c = new Color($this->config->bookShadeColor);
+ $this->lessVariables['shadow-opacity'] = $c->getAlpha() * 1.2;
+ $this->lessVariables['edges-display'] = $this->_lessBoolean($this->config->usePageEdges);
+ $this->lessVariables['edge-left-offset'] = 0;
+ $this->lessVariables['edge-right-offset'] = 0;
+ $this->lessVariables['edges-opacity'] = 1;
+
+
+ $this->lessVariables['page-number-color'] = Color::colorToCSS($this->config->colorPageNumber);
+ $this->lessVariables['display-page-number'] = $this->_lessBoolean($this->config->displayPageNumber);
+ $this->lessVariables['page-transition-duration'] = $this->config->mobileTransitionDuration . 's';
+
+ $corrText = $this->isMobileFirst() ? 0 : 4;
+
+ if ($this->cssSVGScale != 1) {
+ $texts = '.texts{' . wsHTML5::writeCSSUA('transform-origin', 'top left') . ';';
+ $texts .= wsHTML5::writeCSSUA('transform', 'scale(' . round((1 / $this->multiply) * $cssScale * $this->cssSVGScale, 3) . ')') . ';';
+ $texts .= 'width:' . ($wm / $this->cssSVGScale) . 'px; max-width:' . ($wm / $this->cssSVGScale) . 'px;';
+ $texts .= 'height:' . ($hm / $this->cssSVGScale) . 'px; max-height:' . ($hm / $this->cssSVGScale) . 'px;';
+ $texts .= '}';
+ } else {
+ $texts = '.texts{width:' . floor(floatval($w) + $corrText) . 'px;height:' . floor(floatval($h) + $corrText) . 'px;}';
+ }
+
+ $res[] = $texts;
+
+ // Theme
+ $shade = '.page .shade{';
+ $shade .= 'opacity:' . min(($this->config->shadeAlpha * 2) / 100, 1) . ';';
+ $shade .= '}';
+ $res[] = $shade;
+
+ // SVG
+ $res[] = 'svg .fill-c-menu-back{fill:' . Color::colorToCSS($this->config->couleurB) . ';}';
+ $res[] = 'svg .fill-c-menu-text{fill:' . Color::colorToCSS($this->config->subTextColor) . ';}';
+
+ // Background
+ $res[] = $this->_cssBackground();
+
+ // Archives
+ // Header
+ $header = 'header{';
+ $header .= 'height:' . $this->config->menuHeight . 'px;';
+ if ($mi = $this->checkThemeImage($this->config->menuImage)) {
+ $this->vdir->copy($mi, 'data/images/' . $this->config->menuImage);
+ $header .= 'background-image:url(../images/' . $this->config->menuImage . ');';
+ $header .= 'background-repeat:no-repeat;';
+ $header .= 'background-size:100% ' . $this->config->menuHeight . 'px;';
+ } else {
+ // Force redo
+ $header .= 'background-color:' . Color::colorToCSS($this->config->menuColor) . ';';
+ }
+ $header .= '}';
+ $res[] = $header;
+
+ // Logo
+ $logo = '#logo{';
+ if ($l = $this->checkThemeImage($this->config->logo)) {
+ $this->vdir->copy($l, 'data/images/' . $this->config->logo);
+ $dim = CubeIT_Image::getimagesize($l);
+ $logo .= 'background-image:url(../images/' . $this->config->logo . ');width:' . $dim[0] . 'px;height:' . $dim[1] . 'px;';
+ }
+ $logo .= '}';
+ $res[] = $logo;
+
+ // Credits
+ $res[] = 'footer,footer a{color:' . Color::colorToCSS($this->config->creditsColor) . ';}';
+
+ // Arrows
+ $this->lessVariables['arrows-background'] = Color::colorToCSS($this->config->couleurA);
+ $this->lessVariables['arrows-color'] = Color::colorToCSS($this->config->arrowsColor);
+
+ // Loader
+ $this->lessVariables['loader-background-color'] = Color::colorToCSS($this->config->couleurL);
+ $this->lessVariables['loader-foreground-color'] = Color::colorToCSS($this->config->loadingSecColor);
+
+ // Audio description buttons
+ $this->lessVariables['audiodescription-background'] = Color::colorToCSS($this->config->couleurA);
+ $this->lessVariables['audiodescription-color'] = Color::colorToCSS($this->config->couleurA);
+
+ // Links Styles
+ $this->lessVariables['links-color'] = Color::colorToCSS($this->config->linksColor);
+ $this->lessVariables['inlineslideshow-transition-time'] = ((float)$this->config->inlineSlideshowTransitionDuration * 1000) . 'ms';
+ $this->lessVariables['slideshow-caption-size'] = $this->config->slideshowCaptionSize ?: '16px';
+
+ $res = array_merge($res, $links);
+
+ // Bookmarks
+ if (!isset($this->config->bookmarkCornerSize)) {
+ $this->config->bookmarkCornerSize = 10;
+ }
+
+ $this->lessVariables['bookmark-star-disabled-color'] = Color::colorToCSS($this->config->bookmarkStarDisabledColor);
+ $this->lessVariables['bookmark-star-enabled-color'] = Color::colorToCSS($this->config->bookmarkStarEnabledColor);
+ $this->lessVariables['bookmark-color'] = Color::colorToCSS($this->config->bookmarkBackgroundColor);
+ $this->lessVariables['bookmark-corner-size'] = round($this->getWidth() * $this->config->bookmarkCornerSize * 0.0075 * $this->z) . 'px';
+ $this->lessVariables['bookmark-corner-offset'] = $this->config->bookmarkOffset . 'px';
+
+ // Menus
+ $menuColor = new Color($this->config->couleurB);
+ $menuColor->setAlpha(1);
+ $menuTextColor = Color::colorToCSS($this->config->subTextColor);
+ $menuBreakpoint = empty($this->config->menuBreakpoint) ? '1023px' : $this->config->menuBreakpoint;
+
+ $this->lessVariables['menu-breakpoint'] = $menuBreakpoint;
+ $this->lessVariables['menu-background'] = $menuColor->toCSS();
+ if ($this->config->subSecondaryColor) {
+ $this->lessVariables['menu-button-background'] = Color::colorToCSS($this->config->subSecondaryColor);
+ } else {
+ $this->lessVariables['menu-background-green'] = 'max(45, min(255-45, green(@menu-background)))';
+ $this->lessVariables['menu-background-red'] = 'max(45, min(255-45, red(@menu-background)))';
+ $this->lessVariables['menu-background-blue'] = 'max(45, min(255-45, blue(@menu-background)))';
+ $this->lessVariables['menu-button-background'] = 'overlay(rgb(@menu-background-red, @menu-background-green, @menu-background-blue), #c0c0c0)';
+ }
+
+ $this->lessVariables['menu-text'] = $menuTextColor;
+ $this->lessVariables['menu-field-background'] = Color::colorToCSS($this->config->subFieldColor);
+ $this->lessVariables['menu-field-text'] = Color::colorToCSS($this->config->subTextFieldColor);
+ $this->lessVariables['menu-select-background'] = Color::colorToCSS($this->config->subSelectColor);
+ $this->lessVariables['menu-select-text'] = Color::colorToCSS($this->config->subTextSelectColor);
+ $this->lessVariables['icon-color'] = Color::colorToCSS($this->config->couleurI);
+ $this->lessVariables['menu-overlay'] = Color::colorToCSS($this->config->popupVideoOverlay);
+
+ // Chapters
+ $this->lessVariables['menu-chapters-columns-count'] = max(1, min(6, $this->config->chaptersColumns));
+ $this->lessVariables['menu-chapters-columns-width'] = $this->config->chaptersColMaxWidth;
+ $this->lessVariables['menu-chapters-font-size'] = $this->config->chaptersFontSize;
+
+ foreach ($this->book->chapters as $chapter) {
+ if (substr($chapter->page, 0, 1) != '#') {
+ continue;
+ }
+ if ($chapter->color == '') {
+ continue;
+ }
+ $color = trim($chapter->color, '#');
+ $lessContents .= '.mview.c_' . $color . '{.menu-color(' . Color::colorToCSS($color) . ');}';
+ }
+
+ // Archives
+ if ($this->config->externalArchivesBack) {
+ $this->vdir->copy($this->wdir . '/' . $this->config->externalArchivesBack, 'data/images/' . $this->config->externalArchivesBack);
+ $res[] = '.mview.archives{background-image:url("../images/' . $this->config->externalArchivesBack . '");}';
+ }
+
+ # Index
+ $thumbw = $this->config->mobileNavigationType === 'portrait' ? 200 : 100;
+ $this->lessVariables['thumb-width'] = $thumbw . 'px';
+ $ratio = $this->getWidth() / $this->getHeight();
+ $thumbh = round($thumbw / $ratio);
+ $this->config->thumbWidth = $thumbw;
+ $this->config->thumbHeight = $thumbh;
+
+ $this->lessVariables['thumb-height'] = $thumbh . 'px';
+
+ #tooltip
+ $this->lessVariables['tooltip-background'] = Color::colorToCSS($this->config->tooltipBackColor);
+ $this->lessVariables['tooltip-color'] = Color::colorToCSS($this->config->tooltipTextColor);
+ $this->lessVariables['tooltip-font-size'] = 14 * (($this->config->tooltipTextSize ?: 100) / 100);
+
+ #Videos
+ if ($this->config->bigPlayImage) {
+ $this->lessVariables['video-bigplay-image'] = '~"../data/links/' . $this->config->bigPlayImage . '"';
+ $this->vdir->copy($this->wdir . '/' . $this->config->bigPlayImage, 'data/links/' . $this->config->bigPlayImage);
+ } else {
+ $this->lessVariables['video-bigplay-image'] = '~"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTMuNCAxMTMuNCI+PHN0eWxlPi5zdDB7b3BhY2l0eTowLjg7fSAuc3Qxe2ZpbGw6I0ZGRkZGRjt9PC9zdHlsZT48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTEwLjUgMTEzLjRIMi45Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlWMi45QzAgMS4zIDEuMyAwIDIuOSAwaDEwNy42YzEuNiAwIDIuOSAxLjMgMi45IDIuOXYxMDcuNmMwIDEuNi0xLjMgMi45LTIuOSAyLjl6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQ1LjggMzcuOGwzMS41IDE3LjljLjguNS44IDEuNiAwIDIuMUw0NS44IDc1LjZjLS44LjUtMS44LS4xLTEuOC0xVjM4LjhjMC0uOSAxLTEuNSAxLjgtMXoiLz48L3N2Zz4="';
+ }
+
+ #fonts
+ foreach ($this->cssfont as $hash => $item) {
+ $res[] = '@font-face{font-family: "' . $hash . '";src:url("../../data/fonts/' . $hash . '.woff") format("woff");}';
+ }
+
+ if ($this->config->textPopupStylesheet) {
+ $res[] = file_get_contents($this->wdir . '/' . $this->config->textPopupStylesheet);
+ }
+
+ $this->compileLess($this->lessVariables, $lessContents);
+ $this->stylesheets[] = 'data/style/style.css';
+ $this->vdir->file_put_contents('data/style/style.css', implode("\n", $res));
+
+ }
+
+ protected function compileLess($variables, $lessContents = '')
+ {
+ if ($this->widget) {
+ $this->lessFiles[] = 'widget';
+ }
+ foreach ($this->specialCSS as $s) {
+ $this->lessFiles[] = 'special/' . $s;
+ }
+
+ $tmp = CubeIT_Files::tmpdir();
+
+ $from = $this->assets . '/style/*';
+ `cp -r $from $tmp`;
+
+ $bookVariables = array();
+ foreach ($variables as $k => $v) {
+ $bookVariables[] = '@' . trim($k) . ':' . $v . ';';
+ }
+ file_put_contents($tmp . '/book-variables.less', implode("\n", $bookVariables));
+ file_put_contents($tmp . '/additional.less', $lessContents);
+
+ foreach ($this->lessFiles as $f) {
+ $source_less = $this->assets . '/style/' . $f . '.less';
+ $destination_less = $tmp . '/' . $f . '.less';
+ $destination_css = $tmp . '/' . $f . '.css';
+
+ if (!file_exists($source_less)) {
+ die($source_less);
+ continue;
+ }
+
+ $dir = dirname($destination_css);
+
+ if (file_exists($dir) && !is_dir($dir)) {
+ unlink($dir);
+ }
+ // LESS file might be in a subfolder, so create if it doesn't exist
+ if (!file_exists($dir)) {
+ mkdir($dir, 0777, true);
+ }
+
+ // Less files must be copied to temporary directory so they'll
+ // have access to the variables generated in book-variables.less
+ copy($source_less, $destination_less);
+ $less = new CommandLine('lessc');
+ $less->setArg(null, $destination_less);
+ $less->setArg(null, $destination_css);
+ $less->execute();
+ if (!file_exists($destination_css)) {
+ die($less->getOutput());
+ continue;
+ }
+ $this->vdir->copy($destination_css, 'style/' . $f . '.css');
+ if ($f != 'widget') {
+ $this->stylesheets[] = 'style/' . $f . '.css';
+ }
+ }
+ }
+
+ protected function checkThemeImage($path)
+ {
+ $path = trim($path);
+ $path = trim($path, '/');
+ if (!$path) {
+ return false;
+ }
+ $p = $this->themeRoot . '/' . $path;
+ if (file_exists($p)) {
+ return $p;
+ }
+ $po = str_replace('.svg', '.o.svg', $p);
+ if (file_exists($po)) {
+ copy($po, $p);
+ return $p;
+ }
+ return false;
+ }
+
+ protected function _themeBoolean($v): bool
+ {
+ return !(null === $v || $v === '0' || $v === 0 || $v === false || !$v);
+ }
+}