All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wbillingsley.veautiful.templates.VSlides.scala Maven / Gradle / Ivy

package com.wbillingsley.veautiful.templates

import com.wbillingsley.veautiful.html.{<, Styling, DHtmlComponent, VHtmlDiffNode, VHtmlElement, ^}
import com.wbillingsley.veautiful.Morphing
import com.wbillingsley.veautiful.logging.Logger
import org.scalajs.dom
import org.scalajs.dom.raw.{Event, HTMLElement}

object VSlides {
  val logger = Logger.getLogger(VSlides.getClass)

  trait Layout:
    def apply(slides:VSlides, slide:VHtmlElement, index:Int):VHtmlElement

  object DefaultLayout extends Layout:
    def apply(slides:VSlides, slide:VHtmlElement, index:Int):VHtmlElement =
      <.div(
        ^.cls := s"v-slide ${defaultTheme.className}", ^.attr("style") := s"height: ${slides.height}px", slide
      ).build()

  /*
   * Functional styles, e.g. for rescaling
   */
  
  val defaultTheme = Styling(
    """background: white;
      |padding: 50px;
      |display: flex;
      |height: 100%;
      |font-family: sans-serif;
      |font-weight: normal;
      |font-size: 20px;
      |""".stripMargin).modifiedBy(
    "> *:first-child" -> "width: 100%",
    " li" -> "line-height: 200%;",
    " li pre" -> "line-height: 125%;",
    " img" -> "max-height: 75; max-width: 100%;",
    " table > thead > tr > th" -> "text-align: left; padding: 8px;",
    " table > tbody > tr > td" -> "padding: 8px;",
    " table > tbody > tr:nth-of-type(odd)" -> "background-color: #f9f9f9;",
    " a" -> "text-decoration: none;",
    " blockquote" -> "padding: 15px; border-left: 10px solid #aaa;",
    " .center" -> "text-align: center;",
    " .middle" -> "margin-top: auto; margin-bottom: auto;",
    " .byline" -> "color: #aaaaaa;",
    " .notes-only" -> "display: none",
    " .footnote" ->
      """position: fixed;
        |text-align: left;
        |bottom: 10px;
        |left: 20px;
        |font-family: sans-serif;
        |font-size: 18px;
        |color: rgb(120, 120, 120);
        |margin-right: auto;
        |margin-left: auto;
        |""".stripMargin,
    " h1" ->
      """font-family: 'Times New Roman', serif;
        |color: #7d5177;
        |font-weight: normal;
        |margin-top: 0;
        |margin-block-end: 1em;
        |font-variant-caps: normal;
        |""".stripMargin,
    " h2" ->
      """font-family: 'Times New Roman', serif;
        |color: #7d5177;
        |font-weight: normal;
        |margin-top: 0;
        |margin-block-end: 1em;
        |font-variant-caps: normal;
        |""".stripMargin,
    " h3" ->
      """font-family: 'Times New Roman', serif;
        |color: #7d5177;
        |font-weight: normal;
        |margin-top: 0;
        |margin-block-end: 1em;
        |font-variant-caps: normal;
        |""".stripMargin,
    
  ).register()
  
}

case class VSlidesConfig(
  index: Int = 0,
  onIndexChange: Option[Int => Unit] = None,
  sequencerLayout: Sequencer.LayoutFunc = Sequencer.defaultLayout
)


/** VSlides just defines the deck. The layout within the page is part of the definition. */
case class VSlides(
  val width: Int, val height: Int, val content: Seq[SequenceItem], val layout:VSlides.Layout = VSlides.DefaultLayout
) {
  def laidOut = content.zipWithIndex.map { (item, idx)  => layout(this, item, idx) }
}

/** Something that can take a deck, and a page number, and render it to a VDomNode */
type VSlidesPlayer = (VSlides, Int) => VHtmlElement

case class DefaultVSlidesPlayer(deck: VSlides, override val key: Option[String] = None, scaleToWindow:Boolean = true)(
  index: Int = 0,
  onIndexChange: Option[Int => Unit] = None,
  sequencerLayout: Sequencer.LayoutFunc = Sequencer.defaultLayout
) extends DHtmlComponent with Morphing(VSlidesConfig(index, onIndexChange, sequencerLayout)) {
  
  val morpher = createMorpher(this)

  var top:Double = 0
  var left:Double = 0
  
  private val internalOnIndexChange: Int => Unit = { i =>
    prop.onIndexChange match {
      case Some(f) => f(i)
      case None => updateProp(prop.copy(index = i))
    }
  }

  override def render = {
    val config = prop
    
    val sequencer = Sequencer()(
      deck.laidOut, config.index, layout = config.sequencerLayout, Some(internalOnIndexChange)
    )
    
    <.div(
      WindowScaler(deck.width, deck.height)(
        sequencer, scaleToWindow
      )
    )
  }
  
  def atSlide(i:Int):DefaultVSlidesPlayer = DefaultVSlidesPlayer(deck, key)(i, prop.onIndexChange)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy