Skip to content

Instantly share code, notes, and snippets.

@TheSeamau5
Last active August 29, 2015 14:24
Show Gist options
  • Save TheSeamau5/9cd1c9f58d954a517503 to your computer and use it in GitHub Desktop.
Save TheSeamau5/9cd1c9f58d954a517503 to your computer and use it in GitHub Desktop.
import Html exposing (Html)
import Html.Attributes
import Html.Events
import Signal exposing (Address)
import List
import Window
-----------------
-- HELPER CODE --
infixl 2 =>
(=>) = (,)
type alias Vector =
{ x : Float
, y : Float
}
-----------------
type alias State child =
{ children : List child
, cellHeight : Float
, numCols : Int
, gridWidth : Float
}
type Action action
= Child Int action
| Resize Float
type alias Context =
{ index : Int
, total : Int
, row : Int
, column : Int
, size : Vector
}
cellSize : State child -> Vector
cellSize {cellHeight, numCols, gridWidth} =
{ x = gridWidth / (toFloat numCols)
, y = cellHeight
}
gridSize : State child -> Vector
gridSize {children, cellHeight, gridWidth, numCols} =
let
numChildren = List.length children
numRows =
if numCols == 0 then 0 else numChildren // numCols
gridHeight =
toFloat numRows * cellHeight
in
{ x = gridWidth , y = gridHeight }
resize : Float -> State child -> State child
resize size state =
let
numChildren = List.length state.children
numRows =
if state.numCols == 0 then 0 else numChildren // state.numCols + 1
oldGridHeight =
toFloat numRows * state.cellHeight
ratio =
size / state.gridWidth
newCellHeight =
ratio * state.cellHeight
in
{ state | cellHeight <- newCellHeight
, gridWidth <- size
}
update : (Context -> Maybe action -> child -> child) -> Maybe (Action action) -> State child -> State child
update updateChild maybeAction state =
case maybeAction of
Nothing ->
state
Just action ->
case action of
Child n childAction ->
let
updateN index child =
if n == index
then
let
numChildren =
List.length state.children
context =
{ index = n
, size = cellSize state
, total = numChildren
, column = index % state.numCols
, row = index // state.numCols
}
in
updateChild context (Just childAction) child
else
child
in
{ state | children <- List.indexedMap updateN state.children }
Resize width ->
let
gridDims =
gridSize state
ratio =
width / gridDims.x
height =
ratio * gridDims.y
updateN index child =
let
numChildren =
List.length state.children
context =
{ index = index
, size =
{ x = width
, y = height
}
, total = numChildren
, column = index % state.numCols
, row = index // state.numCols
}
in
updateChild context Nothing child
in
resize width { state | children <- List.indexedMap updateN state.children }
view : (Context -> Address action -> child -> Html) -> Address (Action action) -> State child -> Html
view viewChild address state =
let
gridDims =
gridSize state
cellDims =
cellSize state
containerStyles =
[ "position" => "absolute"
, "top" => "0px"
, "left" => "0px"
, "width" => toString gridDims.x ++ "px"
, "height" => toString gridDims.y ++ "px"
]
viewN index child =
let
left =
cellDims.x * toFloat (index % state.numCols)
top =
cellDims.y * toFloat (index // state.numCols)
childContainer =
[ "position" => "absolute"
, "left" => toString left ++ "px"
, "top" => toString top ++ "px"
, "width" => toString cellDims.x ++ "px"
, "height" => toString cellDims.y ++ "px"
-- , "border" => "1px solid black"
]
childAddress =
Signal.forwardTo address (Child index)
numChildren =
List.length state.children
context =
{ index = index
, size = cellDims
, total = numChildren
, column = index % state.numCols
, row = index // state.numCols
}
in
Html.div
[ Html.Attributes.style childContainer ]
[ viewChild context childAddress child ]
in
Html.div
[ Html.Attributes.style containerStyles ]
( List.indexedMap viewN state.children )
------------------------------------------------------------
-- Counter Component
type alias Count = Int
type CountAction
= Increment
| Decrement
updateCount : Context -> Maybe CountAction -> Count -> Count
updateCount _ maybeAction count =
case maybeAction of
Nothing ->
count
Just action ->
case action of
Increment ->
count + 1
Decrement ->
count - 1
viewCount : Context -> Address CountAction -> Count -> Html
viewCount context address count =
let
isOdd =
if context.row % 2 == 0
then
if context.column % 2 == 0
then
True
else
False
else
if context.column % 2 == 0
then
False
else
True
fontSize =
(min context.size.x context.size.y) / 3
(color, backgroundColor) =
if isOdd
then
("white", "black")
else
("black", "white")
containerStyle =
[ "position" => "absolute"
, "top" => "0px"
, "left" => "0px"
, "width" => toString context.size.x ++ "px"
, "height" => toString context.size.y ++ "px"
, "background-color" => backgroundColor
, "color" => color
]
decrementButtonStyle =
[ "position" => "absolute"
, "top" => toString (2 * context.size.y / 3) ++ "px"
, "left" => "0px"
, "width" => toString context.size.x ++ "px"
, "height" => toString (context.size.y / 3) ++ "px"
, "background-color" => backgroundColor
, "color" => color
, "text-align" => "center"
, "cursor" => "pointer"
, "-webkit-user-select" => "none"
, "font-size" => toString fontSize ++ "px"
]
incrementButtonStyle =
[ "position" => "absolute"
, "top" => "0px"
, "left" => "0px"
, "width" => toString context.size.x ++ "px"
, "height" => toString (context.size.y / 3) ++ "px"
, "background-color" => backgroundColor
, "color" => color
, "text-align" => "center"
, "cursor" => "pointer"
, "-webkit-user-select" => "none"
, "font-size" => toString fontSize ++ "px"
]
counterTextStyle =
[ "position" => "absolute"
, "top" => toString (context.size.y / 3) ++ "px"
, "left" => "0px"
, "width" => toString context.size.x ++ "px"
, "height" => toString (context.size.y / 3) ++ "px"
, "text-align" => "center"
, "font-size" => toString fontSize ++ "px"
]
in
Html.div
[ Html.Attributes.style containerStyle ]
[ Html.div
[ Html.Events.onClick address Decrement
, Html.Attributes.style decrementButtonStyle
]
[ Html.text "-" ]
, Html.div
[ Html.Events.onClick address Increment
, Html.Attributes.style incrementButtonStyle
]
[ Html.text "+" ]
, Html.span
[ Html.Attributes.style counterTextStyle ]
[ Html.text (toString count) ]
]
initialCount = 0
-------------------------------------------
-- update : (Context -> Maybe action -> child -> child) -> Maybe (Action action) -> State child -> State child
-- view : (Context -> Address action -> child -> Html) -> Address (Action action) -> State child -> Html
initial : State Count
initial =
{ gridWidth = 400
, cellHeight = 50
, numCols = 8
, children = List.repeat 64 initialCount
}
actionMailbox = Signal.mailbox Nothing
address =
Signal.forwardTo actionMailbox.address Just
resizes =
let
resize (x,_) =
x
|> toFloat
|> Resize
|> Just
in
Signal.map resize Window.dimensions
signal =
Signal.merge
(actionMailbox.signal)
(resizes)
main =
Signal.map (view viewCount address)
(Signal.foldp (update updateCount) initial signal)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment