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

laika.helium.config.layout.scala Maven / Gradle / Ivy

/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package laika.helium.config

import laika.ast.Path.Root
import laika.ast._
import laika.parse.{GeneratedSource, SourceFragment}

private[helium] sealed trait CommonLayout {
  def defaultBlockSpacing: Length
  def defaultLineHeight: Double
}

private[helium] case class WebLayout(contentWidth: Length,
                                     navigationWidth: Length,
                                     topBarHeight: Length,
                                     defaultBlockSpacing: Length,
                                     defaultLineHeight: Double,
                                     anchorPlacement: AnchorPlacement) extends CommonLayout

private[helium] case class WebContent(favIcons: Seq[Favicon] = Nil,
                                      htmlIncludes: HTMLIncludes = HTMLIncludes(),
                                      topNavigationBar: TopNavigationBar = TopNavigationBar.default,
                                      mainNavigation: MainNavigation = MainNavigation(),
                                      pageNavigation: PageNavigation = PageNavigation(),
                                      footer: Option[TemplateSpan] = Some(HeliumFooter.default),
                                      landingPage: Option[LandingPage] = None,
                                      tableOfContent: Option[TableOfContent] = None,
                                      downloadPage: Option[DownloadPage] = None)

private[helium] case class PDFLayout (pageWidth: Length, pageHeight: Length,
                                      marginTop: Length, marginRight: Length, marginBottom: Length, marginLeft: Length,
                                      defaultBlockSpacing: Length,
                                      defaultLineHeight: Double,
                                      keepTogetherDecoratedLines: Int,
                                      tableOfContent: Option[TableOfContent] = None) extends CommonLayout

private[helium] case class EPUBLayout (defaultBlockSpacing: Length,
                                       defaultLineHeight: Double,
                                       keepTogetherDecoratedLines: Int,
                                       tableOfContent: Option[TableOfContent] = None) extends CommonLayout

private[helium] case class TableOfContent (title: String, depth: Int)

private[helium] case class TopNavigationBar (homeLink: ThemeLink, 
                                             navLinks: Seq[ThemeLink],
                                             versionMenu: VersionMenu = VersionMenu.default,
                                             highContrast: Boolean = false)

private[helium] object TopNavigationBar {
  def withHomeLink (path: Path): TopNavigationBar = TopNavigationBar(IconLink.internal(path, HeliumIcon.home), Nil)
  val default: TopNavigationBar = TopNavigationBar(DynamicHomeLink.default, Nil)
}

object HeliumFooter {
  val default: TemplateSpanSequence = TemplateSpanSequence.adapt(
    TemplateString("Site generated by "),
    SpanLink.external("https://planet42.github.io/Laika/")("Laika"),
    TemplateString(" with the Helium theme.")
  )
}

private[helium] case class MainNavigation (depth: Int = 2,
                                           includePageSections: Boolean = false,
                                           prependLinks: Seq[ThemeNavigationSection] = Nil,
                                           appendLinks: Seq[ThemeNavigationSection] = Nil)

private[helium] case class PageNavigation (enabled: Boolean = true,
                                           depth: Int = 2,
                                           sourceBaseURL: Option[String] = None,
                                           sourceLinkText: String = "Source for this page")

private[helium] case class DownloadPage (title: String, description: Option[String], downloadPath: Path = Root / "downloads", 
                                        includeEPUB: Boolean = true, includePDF: Boolean = true)

private[helium] case class LandingPage (logo: Option[Image] = None,
                                        title: Option[String] = None,
                                        subtitle: Option[String] = None,
                                        latestReleases: Seq[ReleaseInfo] = Nil,
                                        license: Option[String] = None,
                                        titleLinks: Seq[ThemeLink] = Nil,
                                        documentationLinks: Seq[TextLink] = Nil,
                                        projectLinks: Seq[ThemeLinkSpan] = Nil,
                                        teasers: Seq[Teaser] = Nil,
                                        styles: Seq[Path] = Nil) {
  
  import LengthUnit._
  
  val subtitleFontSize: Length =
    if (subtitle.exists(_.length > 75)) px(22)
    else if (subtitle.exists(_.length > 55)) px(27)
    else px(32)
  
  val teaserTitleFontSize: Length = if (teasers.size <= 4) px(28) else px(20)
  val teaserBodyFontSize: Length = if (teasers.size <= 4) px(17) else px(15)
  
}

/** In contrast to the public `LinkGroup` this UI component allows all types of links as children, including menus.
  */
private[helium] case class GenericLinkGroup (links: Seq[ThemeLink], options: Options = NoOpt) extends BlockResolver {
  type Self = GenericLinkGroup
  val source: SourceFragment = GeneratedSource
  def resolve (cursor: DocumentCursor): Block = {
    val resolvedLinks = links.map {
      case sr: SpanResolver => SpanSequence(sr.resolve(cursor))
      case br: BlockResolver => br.resolve(cursor)
    }
    BlockSequence(resolvedLinks, HeliumStyles.linkRow + options)
  } 
  def withOptions(newOptions: Options): GenericLinkGroup = new GenericLinkGroup(links, newOptions) {}
  def unresolvedMessage: String = s"Unresolved link group: $this"
  def runsIn (phase: RewritePhase): Boolean = phase.isInstanceOf[RewritePhase.Render]
}

/** Configuration for a single favicon which can be an internal resource or an external URL.
  * 
  * The sizes string will be used in the corresponding `sizes` attribute of the generated `<link>` tag.
  */
case class Favicon private (target: Target, sizes: Option[String] = None, mediaType: Option[String] = None)

/** Companion for creating Favicon configuration instances.
  */
object Favicon {
  private def mediaType (suffix: Option[String]): Option[String] = suffix.collect {
    case "ico" => "image/x-icon"
    case "png" => "image/png"
    case "gif" => "image/gif"
    case "jpg" | "jpeg" => "image/jpeg"
    case "svg" => "image/svg+xml"
  }

  /** Creates the configuration for a single favicon with an external URL.
    *
    * The sizes string will be used in the corresponding `sizes` attribute of the generated `<link>` tag.
    */
  def external (url: String, sizes: String, mediaType: String): Favicon = 
    Favicon(ExternalTarget(url), Some(sizes), Some(mediaType))

  /** Creates the configuration for a single favicon with an external URL.
    */
  def external (url: String, mediaType: String): Favicon =
    Favicon(ExternalTarget(url), None, Some(mediaType))

  /** Creates the configuration for a single favicon based on an internal resource and its virtual path.
    * This resource must be part of the inputs known to Laika.
    *
    * The sizes string will be used in the corresponding `sizes` attribute of the generated `<link>` tag.
    */
  def internal (path: Path, sizes: String): Favicon = 
    Favicon(InternalTarget(path), Some(sizes), mediaType(path.suffix))

  /** Creates the configuration for a single favicon based on an internal resource and its virtual path.
    * This resource must be part of the inputs known to Laika.
    */
  def internal (path: Path): Favicon =
    Favicon(InternalTarget(path), None, mediaType(path.suffix))
}

/** Represents release info to be displayed on the landing page.
  * 
  * This is specific for sites that serve as documentation for software projects.
  * 
  * @param title the header above the version number, e.g. "Latest Stable Release"
  * @param version the version number of the release
  */
case class ReleaseInfo (title: String, version: String)

/** Represents a single teaser block to be displayed on the landing page.
  * Any number of these blocks can be passed to the Helium configuration.
  */
case class Teaser (title: String, description: String)

/** Configures the anchor placement for section headers.
  * Anchors appear on mouse-over and allow to copy the direct link to the section.
  */
sealed trait AnchorPlacement

object AnchorPlacement {
  /** Disables anchors for all section headers. */
  object None extends AnchorPlacement
  /** Places anchors to the left of section headers. */
  object Left extends AnchorPlacement
  /** Places anchors to the right of section headers. */
  object Right extends AnchorPlacement
}

private[helium] case class HTMLIncludes (includeCSS: Seq[Path] = Seq(Root), includeJS: Seq[Path] = Seq(Root))

private[helium] object HeliumStyles {
  val row: Options = Styles("row")
  val linkRow: Options = Styles("row", "links")
  val buttonLink: Options = Styles("button-link")
  val textLink: Options = Styles("text-link")
  val iconLink: Options = Styles("icon-link")
  val imageLink: Options = Styles("image-link")
  val menuToggle: Options = Styles("menu-toggle")
  val menuContainer: Options = Styles("menu-container")
  val menuContent: Options = Styles("menu-content")
  val versionMenu: Options = Styles("version-menu")
}

private[helium] case class ThemeFonts (body: String, headlines: String, code: String)

private[helium] case class FontSizes (body: Length, code: Length, title: Length, header2: Length, header3: Length, header4: Length, small: Length)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy