Use bootstrap styles.

Better than anything I can do in a short period of time!
This commit is contained in:
Danila Fedorin 2019-05-29 18:29:18 -07:00
parent 5710f10999
commit 6a06a99529
3 changed files with 87 additions and 182 deletions

View File

@ -1,6 +1,7 @@
<html>
<head>
<script src="/static/js/elm.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>

View File

@ -4,30 +4,68 @@ import CacheSim.Model exposing (..)
import CacheSim.Cache exposing (..)
import CacheSim.AccessView exposing (..)
import CacheSim.Hierarchy exposing (..)
import Html exposing (Html, input, text, div, label, span, h2, h3, table, tr, td)
import Html.Attributes exposing (type_, class, value, for, classList, disabled, colspan)
import Html exposing (Html, Attribute, input, text, div, label, span, h2, h3, table, tr, td, th)
import Html.Attributes exposing (type_, class, value, for, classList, disabled, colspan, hidden)
import Html.Events exposing (onInput, onClick)
optionalButton : Bool -> String -> Msg -> Html Msg
optionalButton e s m =
let
events = if e then [ onClick m ] else [ disabled (not e) ]
in
input ([ type_ "button", value s ] ++ events) []
-- Button components, powered by Bootstrap
basicButton : List (Attribute Msg) -> String -> Html Msg
basicButton attrs s = input ([ type_ "button", value s, class "btn", class "btn-info" ] ++ attrs) []
disabledButton : String -> Html Msg
disabledButton = basicButton [ disabled True ]
advancedButton : List (Attribute Msg) -> String -> Msg -> Html Msg
advancedButton attrs s m = basicButton (attrs ++ [ onClick m ]) s
button : String -> Msg -> Html Msg
button s m = input [ type_ "button", onClick m, value s] []
button s m = basicButton [ onClick m ] s
dangerButton : String -> Msg -> Html Msg
dangerButton = advancedButton [ class "btn-danger" ]
primaryButton : String -> Msg -> Html Msg
primaryButton = advancedButton [ class "btn-primary" ]
secondaryButton : String -> Msg -> Html Msg
secondaryButton = advancedButton [ class "btn-secondary" ]
maybeButton : Maybe a -> String -> (a -> Msg) -> Html Msg
maybeButton m s f =
case m of
Just v -> button s (f v)
_ -> disabledButton s
resultButton : Result e a -> String -> (a -> Msg) -> Html Msg
resultButton = maybeButton << Result.toMaybe
-- Button wrapper (button group)
buttonWrapper : List (Html Msg) -> Html Msg
buttonWrapper = div [ class "button-wrapper" ]
buttonWrapper = div [ classList [("btn-group", True), ("mb-3", True) ] ]
-- Input with a label
labeledInput : String -> String -> (String -> Msg) -> Html Msg
labeledInput s val f =
div [ class "input-group" ]
[ span [] [ text s ]
, input [ value val, type_ "text", onInput f ] []
div [ class "input-group mb-3" ]
[ div [ class "input-group-prepend" ]
[ span [ class "input-group-text" ] [ text s ]
]
, input [ value val, type_ "text", class "form-control", onInput f ] []
]
-- Error view
viewError : Bool -> String -> Html Msg
viewError hide e = div
[ classList
[ ("alert", True)
, ("alert-danger", True)
]
, hidden hide
] [ text e ]
panel : List (Html Msg) -> Html Msg
panel = div [ classList [("card", True), ("p-3", True), ("mb-3", True) ] ]
viewRawCacheModel : Int -> RawCacheModel -> Html Msg
viewRawCacheModel level rcm =
let
@ -36,15 +74,15 @@ viewRawCacheModel level rcm =
updateSetSize s cm = { cm | setSize = s}
wrapUpdate f s = ChangeRawModel level (f s)
deleteButton = button "Delete" (DeleteRawModel level)
deleteButton = dangerButton "Delete" (DeleteRawModel level)
params = div [ class "cache-model-params" ]
params = div []
[ labeledInput "Block size" rcm.blockSize (wrapUpdate updateBlockSize)
, labeledInput "Set count" rcm.setCount (wrapUpdate updateSetCount)
, labeledInput "Set size" rcm.setSize (wrapUpdate updateSetSize)
]
in
div [ class "cache-model" ]
panel
[ h3 [] [ text <| "L" ++ String.fromInt (level + 1) ++ " Cache" ]
, buttonWrapper [ deleteButton ]
, params
@ -57,21 +95,15 @@ viewRawCacheModelHierarchy rcmh =
<| List.indexedMap viewRawCacheModel rcmh
translationResult = Result.andThen validateCacheModelHierarchy
<| translateRawCacheModelHierarchy rcmh
isValid =
case translationResult of
Ok _ -> True
Err _ -> False
errorHtml =
case translationResult of
Ok _ -> viewError True ""
Err e -> viewError False e
newButton = button "Add level" CreateRawModel
useButton = case translationResult of
Ok cmh -> optionalButton True "Use hierarchy" (UseHierarchy <| Just cmh)
Err _ -> optionalButton False "Use hierarchy" (UseHierarchy Nothing)
useButton = resultButton translationResult "Use hierarchy" (UseHierarchy << Just)
in
div [ class "cache-model-hierarchy" ]
div []
[ h2 [] [ text "Cache hierarchy" ]
, errorHtml
, buttonWrapper [ newButton, useButton ]
@ -84,14 +116,14 @@ viewCache level (cm, cs) =
slotLabels =
List.indexedMap (\i _ -> td [] [ text <| String.fromInt i ])
<| List.repeat cm.setSize ()
slotLabel = td [ colspan cm.setSize ] [ text "Slot" ]
slotLabel = th [ colspan cm.setSize ] [ text "Slot" ]
allSlotLabels = List.concat <| List.repeat cm.setCount slotLabels
allSlotsLabel = List.repeat cm.setCount slotLabel
setLabels =
List.indexedMap (\i _ -> td [ colspan cm.setSize ] [ text <| String.fromInt i ])
<| List.repeat cm.setCount ()
setLabel = [ td [ colspan <| cm.setSize * cm.setCount ] [ text "Set" ] ]
setLabel = [ th [ colspan <| cm.setSize * cm.setCount ] [ text "Set" ] ]
setRow set =
let
slotHtml s =
@ -102,17 +134,17 @@ viewCache level (cm, cs) =
List.map slotHtml set
cacheRow = List.concat <| List.map setRow cs
cacheTable =
table []
[ tr [ classList [("hidden", cm.setCount == 1)] ] setLabel
, tr [ classList [("hidden", cm.setCount == 1)] ] setLabels
, tr [ classList [("hidden", cm.setSize == 1)] ] allSlotsLabel
, tr [ classList [("hidden", cm.setSize == 1)] ] allSlotLabels
table [ class "table" ]
[ tr [ hidden (cm.setCount == 1), class "table-info" ] setLabel
, tr [ hidden (cm.setCount == 1) ] setLabels
, tr [ hidden (cm.setSize == 1), class "table-info" ] allSlotsLabel
, tr [ hidden (cm.setSize == 1) ] allSlotLabels
, tr [] cacheRow
]
in
div [ class "cache" ]
[ h3 [] [ text <| "L" ++ String.fromInt level ++ " Cache" ]
panel
[ h3 [] [ text <| "L" ++ String.fromInt (level + 1) ++ " Cache" ]
, cacheTable
]
@ -122,7 +154,7 @@ viewCacheHierarchy ch =
levels = div [ class "cache-levels" ]
<| List.indexedMap viewCache ch
in
div [ class "cache-hierarchy" ] <|
div [] <|
[ h2 [] [ text <| "Cache State" ]
, levels
]
@ -132,11 +164,11 @@ viewAccessView m av =
let
currentCache = Maybe.withDefault [] m.hierarchy
in
div [ class "access-view" ]
div []
[ h2 [] [ text "Access Simulation" ]
, buttonWrapper
[ button "Forward" AccessViewForward
, button "Back" AccessViewBack
[ primaryButton "Back" AccessViewBack
, primaryButton "Forward" AccessViewForward
]
, viewAccessLog av
, viewCacheHierarchy <| effectiveCacheHierarchy currentCache av
@ -145,12 +177,11 @@ viewAccessView m av =
viewAccessLog : AccessView -> Html Msg
viewAccessLog (aes, ap) =
let
resultSpan r =
case r of
Hit -> span [ class "success" ] [ text "HIT" ]
Miss -> span [ class "failure" ] [ text "MISS" ]
resultSpan r =
span [ classList [ ("badge", True), ("badge-danger", True), ("badge-success", r == Hit) ] ]
[ text <| if r == Hit then "Hit" else "Miss" ]
downEvent n ae = div [ class "event" ]
[ text <| "L" ++ String.fromInt (n + 1)
[ text <| "L" ++ String.fromInt (n + 1) ++ " "
, resultSpan ae.result
]
upEvent n ae = div [ class "event" ]
@ -163,35 +194,32 @@ viewAccessLog (aes, ap) =
Up n -> List.indexedMap downEvent aes ++
(List.indexedMap upEvent <| List.drop n aes)
in
div [ class "access-log" ]
div [ ]
[ h3 [] [ text "Simulation events" ]
, div [ class "access-log-events" ] events
, div [] events
]
viewAccessInput : Model -> Html Msg
viewAccessInput m =
let
accessButton =
case String.toInt m.accessInput of
Just i -> optionalButton True "Access address" (Access i)
Nothing -> optionalButton False "Access address" (Access -1)
accessButton = maybeButton (String.toInt m.accessInput) "Access address" Access
in
div [ class "access-input" ]
div []
[ h2 [] [ text "Run access simulation" ]
, div [ class "note" ]
, div [ classList [("alert", True), ("alert-primary", True)] ]
[ text "Please make sure to click \"Use Hierarchy\" to load a hierarchy to simulate."
]
, labeledInput "Access address" m.accessInput ChangeAccessInput
, accessButton
]
viewError : Bool -> String -> Html Msg
viewError hide e = div [ classList [ ("hidden", hide), ("error", True) ] ] [ text e ]
viewBase : Model -> Html Msg
viewBase m =
let
rawView = viewRawCacheModelHierarchy m.rawHierarchy
rawView =
case m.accessView of
Nothing -> [ viewRawCacheModelHierarchy m.rawHierarchy ]
Just _ -> []
cacheView =
case m.accessView of
Nothing ->
@ -201,4 +229,5 @@ viewBase m =
accessView = Maybe.withDefault [] <| Maybe.map (List.singleton << viewAccessView m) <| m.accessView
accessInputView = [ viewAccessInput m ]
in
div [] <| [ rawView ] ++ cacheView ++ accessView ++ accessInputView
div [ class "container" ]
<| rawView ++ cacheView ++ accessView ++ accessInputView

View File

@ -1,128 +1,3 @@
@import url('https://fonts.googleapis.com/css?family=Raleway&display=swap');
$primary-color: lighten(#26c176, 30%);
body {
font-family: Raleway, serif;
}
h1, h2, h3, h4, h5, h6 {
margin-bottom: 5px;
margin-top: 5px;
}
.hidden {
display: none;
}
.input-group {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 5px;
span {
margin-right: 10px;
}
input {
flex-grow: 1;
}
}
input[type="text"] {
padding: 5px;
border-radius: 5px;
border: none;
background-color: #efefef;
&:active, &:focus {
background-color: $primary-color;
transition: .25s;
}
}
.error {
box-sizing: border-box;
padding: 5px;
border-radius: 5px;
margin-bottom: 10px;
border: 2px solid tomato;
color: tomato;
}
.note {
box-sizing: border-box;
padding: 5px;
border-radius: 5px;
margin-bottom: 10px;
}
span.success {
margin-left: 10px;
color: green;
}
span.failure {
margin-left: 10px;
color: tomato;
}
button, input[type="button"] {
box-sizing: border-box;
border: none;
margin-right: 5px;
margin-bottom: 5px;
display: inline-block;
padding: 5px;
border-radius: 5px;
font-size: 14px;
&:hover, &:focus {
background-color: $primary-color;
transition: .25s;
&:disabled {
background-color: lightgrey;
}
}
}
.cache-model-levels {
display: flex;
flex-wrap: wrap;
}
.cache-model {
max-width: 600px;
padding: 10px;
border-radius: 5px;
border: 2px solid lightgrey;
margin: 5px;
}
.cache, .cache-model {
padding: 10px;
border-radius: 5px;
border: 2px solid lightgrey;
margin: 5px;
}
.cache-model-hierarchy, .cache-hierarchy, .access-input {
margin-bottom: 10px;
}
table {
width: 100%;
}
tr {
&:nth-child(1), &:nth-child(3) {
background-color: $primary-color;
}
}
td {
text-align: center;
padding: 3px;
.btn-group {
width: min-content;
}