Main.hs

» see on github

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Clay hiding (i, s, id)
import Control.Monad
import Data.Monoid
import Prelude hiding (div, span)
import System.Environment

import qualified Clay.Media        as Media
import qualified Data.Text.Lazy.IO as Text

import Codeblock
import Common
import Header

-- When running the stylesheet we allow the generation of compacted CSS by
-- using 'compact' as the first argument. Otherwise we dump the default
-- pretty printed version.

main :: IO ()
main =
  do args <- getArgs
     case args of
       "compact" : _
          -> Text.putStr (renderWith compact theStylesheet)
       _  -> putCss theStylesheet

---------------------------------------------------------------------------

theStylesheet :: Css
theStylesheet =

  do -- Overall site-wide styling rules.
     body ?
       do sym margin  0
          sym padding 0 
          ".index" & "#container" ?
            paddingTop 360

     -- The site consists out of a header with a logo and navigation,
     -- several sections and a footer. We have common style rules for the
     -- sections and allow specific styling for the header and footer.

     theSections
     header ? theHeader
     footer ? theFooter

---------------------------------------------------------------------------

-- Generic styling that every section shares.

theSections :: Css
theSections =

  do section ?

       do boxSizing borderBox
          [paddingTop, paddingBottom] `forM_` ($ 60)

          -- Hack to prevent margin collapse between headers and previous
          -- section.
          borderTop solid (px 1) transparent

          div <?
            do -- Horizontally center the content div inside a section.
               centered

               -- Allow a bit of spacing even when the screen is small.
               sym2 padding 0 (px 10)

          -- Add some style aspects to the sections.
          ".one-col" ? oneColumn
          ".two-col" ? oneOrTwoColumns
          codeblocks
          textblocks

     -- Every odd section (or the footer) gets a slightly distinguished
     -- background color.

     (section <> footer) # nthChild "odd" ?
       backgroundColor trdColor

-- One and two column layouts.

oneColumn :: Css
oneColumn =
  do width (px 550)
     boxSizing borderBox

oneOrTwoColumns :: Css
oneOrTwoColumns =
  do query Clay.all [Media.minWidth 800] twoColumns
     query Clay.all [Media.maxWidth 800] oneColumn

twoColumns :: Css
twoColumns =

  do -- Both columns are have the size of their parent.
     div <?
       do width      (pct 50)
          boxSizing  borderBox

     -- Float first child to the left, second to the right.
     column "1" floatLeft  paddingRight
     column "2" floatRight paddingLeft

     -- Don't float outside the section.
     br ? clear both

  where column i side pad =
          div # nthChild i <?
            do float  side
               pad    (px 30)

---------------------------------------------------------------------------

-- Content blocks containing running texts.

textblocks :: Css
textblocks = ".text" ?

  do textFont
     anchors

     -- Small caps for anchors.
     h3 ?
       do textTransform  uppercase
          color          (sndColor -. 80)
          fontWeight     bold

     -- A bit less padding for lists.
     ul ? paddingLeft (px 20)

     -- Inline code snippets.
     code ? color "#ff4422"

     -- Slightly indent the goto links.
     ".goto" ? paddingLeft (px 25)

---------------------------------------------------------------------------

theFooter :: Css
theFooter = div <?
  do centered
     width          (px 550)
     textFont
     fontSize       (px 12)
     textTransform  uppercase
     textAlign      (alignSide sideCenter)
     color          (setA 150 black)
     sym2 padding   (px 10) 0

Common.hs

» see on github

{-# LANGUAGE OverloadedStrings #-}
module Common where

import Clay

-- The color palette.

fstColor, sndColor, trdColor :: Color

fstColor = rgb 255 160 50
sndColor = rgb 56 135 190
trdColor = "#f8f8f8"

---------------------------------------------------------------------------

textFont, headerFont, codeFont, anchors :: Css

-- Font used for default text blocks.

textFont =
  do fontSize       (px 20)
     lineHeight     (px 30)
     fontFamily     ["Europa", "Helvetica"] [sansSerif]
     textRendering  optimizeLegibility
     color "#222"

-- For now the header uses the default font without the line-height.

headerFont =
  do textFont
     lineHeight inherit

-- Font used for code blocks.

codeFont =
  do fontSize       (px 16)
     fontFamily     ["Monaco", "Courier New"] [monospace]
     lineHeight     (ex 2.6)
     textRendering  optimizeLegibility

-- Generic anchor styling.

anchors =
  a ? do textDecoration  none

         -- Subtle transition.
         transitions [ ("background-color" , sec 0.5, ease, sec 0)
                     , ("color"            , sec 0.2, ease, sec 0)
                     ]

         backgroundColor         (setA   0 yellow)
         hover & backgroundColor (setA  60 yellow)
         color                   sndColor
         hover & color           black

---------------------------------------------------------------------------

-- Helper rule to horizontally center content divs.

centered :: Css
centered =
  do width        (px 800)
     boxSizing    borderBox
     sym2 margin  0 auto

Codeblock.hs

» see on github

{-# LANGUAGE OverloadedStrings #-}
module Codeblock where

import Prelude hiding (div)
import Clay
import Common (codeFont, sndColor)

codeblocks :: Css
codeblocks =

  do isCode ?

       do -- Quite some spacing at the top and bottom, horizontal scrolling
          -- when needed and a slight shadow.

          boxSizing         borderBox
          sym borderRadius  (px 2)
          overflowX         auto
          sym padding       20
          marginTop         (px 60)
          marginBottom      (px 60)
          boxShadow         0 0 (px 60)
                            (setA 30 black)

          pre ?
            do sym margin 0
               codeFont

          -- Specific styling for different languages.

          ".haskell" & haskell
          ".shell"   & haskell -- for now
          ".css"     & css

     -- Reduce the margin between two consecutive code blocks. One is
     -- probably the output of the other and belong closely together.

     isCode |+ isCode ? marginTop (px (-40))

-- How to recognize code blocks.

isCode :: Selector
isCode = div # ".code"

---------------------------------------------------------------------------

-- Haskell code we highlight with a dark background by default.

haskell :: Css
haskell =
  do background (sndColor -. 150)
     pre ?
       do color (setA 160 white)
          ".Comment"  ? color (setA 170 lime)
          ".ConId"    ? color (sndColor +. 100)
          ".Function" ? color white
          ".Keyword"  ? color (sndColor +. 20)
          ".Number"   ? color (setG 100 orange)
          ".String"   ? color (setG 40 red)
          ".Symbol"   ? color orange

---------------------------------------------------------------------------

-- CSS code we highlight with a lighter background by default and we make
-- the font a bit smaller because the generated CSS tends to grow.

css :: Css
css =
  do backgroundColor none
     pre ?
       do fontSize  (px 14)
          color     "#456"
          ".Number"   ? color red
          ".Property" ? color black
          ".Selector" ? color (sndColor -. 60)
          ".String"   ? color red
          ".Symbol"   ? color (orange -. 60)

Header.hs

» see on github

{-# LANGUAGE OverloadedStrings #-}
module Header where

import Clay hiding (i, s, id)
import Control.Monad
import Data.Monoid
import Prelude hiding (div, span)

import Common

---------------------------------------------------------------------------

-- Styling for the header section.

theHeader :: Css
theHeader =

  do -- Make header stick on top of the page.
     position  fixed
     top       (px 0)
     left      (px 0)
     right     (px 0)
     height    (px 240)

     background (vGradient (fstColor -. 80) (fstColor +. 20))
     headerFont

     -- Overlay the interlaced effect.
     before & interlaced

     nav      ? theMenu
     "#logo" <? theLogo

interlaced :: Css
interlaced =

  do mapM_ ($ px 0)
       [ top
       , bottom
       , left
       , right
       ]
     position         absolute

     content          (stringContent "")
     pointerEvents    none
     backgroundSize   (pct 100 `by` px 5)
     backgroundImage  ( repeatingLinearGradient (straight sideTop)
                        [ ( setA  0 white,   0)
                        , ( setA 20 white,  50)
                        , ( setA  0 white, 100)
                        ]
                      )

---------------------------------------------------------------------------

theMenu :: Css
theMenu =

  do let h = 60
     boxSizing      borderBox
     position       absolute
     left           0
     right          0
     bottom         (px (-h))
     height         (px h)

     background     (setA 249 white)
     boxShadow      0 0 (px 60) (setA 20 black)

     lineHeight     (px h)
     fontSize       (px 19)
     textTransform  uppercase


     div <?
       do centered
          width      (px 530)
          textAlign  (alignSide sideCenter)

     a ? do paddingRight    (px 5)
            transition      "color" (sec 0.4) ease (sec 0)
            textDecoration  none
            color           sndColor

            lastOfType & paddingRight (px 0)
            hover & color black

---------------------------------------------------------------------------

-- The site logo.

theLogo :: Css
theLogo =

  do centered
     width          (px 550)

     paddingTop     (px 40)
     height         (pct 100)
     overflow       hidden

     backgroundImage $
       radialGradient sideCenter (ellipse closestSide)
         [ ( setA 150 yellow ,  0 )
         , ( setA  25 yellow , 50 )
         , ( setA   0 yellow , 75 )
         ]

     a ?
       do textDecoration none
          color inherit

     h1 <> h2 ?
       do textTransform  uppercase
          textAlign      (alignSide sideCenter)
          sym margin     0

     h1 ?
       do fontSize    (px 90)
          color       (setA 200 white)
          textShadow  0 0 (px 20) (setA 200 (fstColor -. 80))
          fontWeight  normal

          -- Some custom kerning.
          letterSpacing                (em 0.40)
          span # ".a" ? letterSpacing  (em 0.36)
          span # ".y" ? letterSpacing  (em 0.00)

     h2 ?
       do fontSize       (px 35)
          color          (setA 120 black)
          letterSpacing  (em 0.3)
          a # hover ? color (setA 220 black)