summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Benjamin Barenblat <benjamin@barenblat.name>2017-01-16 16:06:09 -0500
committerGravatar Benjamin Barenblat <benjamin@barenblat.name>2017-01-16 16:06:09 -0500
commit59e04bbb5acde9e2ce209ee43bad9c134debe4d4 (patch)
tree34d0870c9e228a76aef72f9276658882f6f66b78
parentd457eb2a8778d23bf98a8593b5083a2750b0e05a (diff)
Add floating action button
Abstract ripple effect, as it’s shared between the button and the checkboxes.
-rw-r--r--main.ur4
-rw-r--r--material/lib.urp1
-rw-r--r--material/material.css42
-rw-r--r--material/material.ur129
-rw-r--r--material/material.urs6
5 files changed, 126 insertions, 56 deletions
diff --git a/main.ur b/main.ur
index 5e2eab2..1f540f8 100644
--- a/main.ur
+++ b/main.ur
@@ -1,4 +1,4 @@
-(* Copyright 2016 Benjamin Barenblat
+(* Copyright 2016, 2017 Benjamin Barenblat
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
@@ -47,6 +47,7 @@ datatype mode = NextActions | NewNextAction
val main =
actionItems <- bind renderNextActions source;
mode <- source NextActions;
+ floatingActionButton <- Material.FloatingActionButton.make "add";
return (Material.page {
Head = <xml>
(* TODO(bbaren): Write a meta-description tag. *)
@@ -76,6 +77,7 @@ val main =
{Material.List.SingleLine.make <xml>
<dyn signal={signal actionItems} />
</xml>}
+ {floatingActionButton}
</div>
</xml>
})
diff --git a/material/lib.urp b/material/lib.urp
index 0f75854..f6f779e 100644
--- a/material/lib.urp
+++ b/material/lib.urp
@@ -1,3 +1,4 @@
file /material.css material.css
+rewrite style Material/materialIcon material-icons
material \ No newline at end of file
diff --git a/material/material.css b/material/material.css
index 0a762f2..bdc63a6 100644
--- a/material/material.css
+++ b/material/material.css
@@ -24,6 +24,15 @@ html, body {
z-index: 0;
}
+.Material_Ripple_ink {
+ display: block;
+ position: fixed;
+ transform: scale(0);
+ background: #fafafa;
+ border-radius: 100%;
+ animation: ripple 300ms linear;
+}
+
.Material_AppBar_bar {
background: #9c27b0;
height: 56px;
@@ -69,22 +78,35 @@ html, body {
background: #9c27b0 url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K);
}
-.Material_Checkbox_ink {
- display: block;
- position: fixed;
- transform: scale(0);
+.Material_Checkbox_container .Material_Ripple_ink {
background: #9c27b0; /* TODO(bbaren): Is this the correct color? */
- border-radius: 100%;
- animation: ripple 300ms linear;
-
- /* These must match the width and height defined in Material.Checkbox. */
- width: 24px;
- height: 24px;
/* Place the ripple effect underneath the checkmark. */
z-index: -1;
}
+.Material_FloatingActionButton_container {
+ width: 56px;
+ height: 56px;
+ position: fixed;
+ right: 16px;
+ bottom: 16px;
+ border-radius: 100%;
+ overflow: hidden;
+ box-shadow: 0px 6px 12px 0px rgba(0,0,0,0.34); /* 6dp */
+}
+
+.Material_FloatingActionButton_element {
+ width: 100%;
+ height: 100%;
+ background: #ff9800;
+ border: none;
+
+ /* Black text on orange looks a bit weird, but the MDL color picker says that’s
+ correct, so.... */
+ color: #000;
+}
+
.Material_List_SingleLine_element {
list-style-type: none;
height: 48px;
diff --git a/material/material.ur b/material/material.ur
index 72a3e98..f63bec0 100644
--- a/material/material.ur
+++ b/material/material.ur
@@ -12,13 +12,52 @@ 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. *)
+style materialIcon
style stackingContext
+fun icon s = <xml><i class={materialIcon}>{[s]}</i></xml>
+
fun inNewStackingContext x = <xml><div class={stackingContext}>{x}</div></xml>
+structure Ripple : sig
+ val inkAnimation : int -> int -> source (option {X : int, Y : int}) -> xbody
+end = struct
+ style ink
+
+ fun inkStyle width height xy =
+ let
+ fun p a b = value (property a) (atom (show b ^ "px"))
+ in
+ oneProperty
+ (oneProperty
+ (oneProperty
+ (oneProperty noStyle
+ (p "width" width))
+ (p "height" height))
+ (p "left" (xy.X - width / 2)))
+ (p "top" (xy.Y - height / 2))
+ end
+
+ fun inkAnimation width height s =
+ <xml>
+ <dyn
+ signal={
+ v <- signal s;
+ return (case v of
+ None => <xml></xml>
+ | Some xy => <xml>
+ <span class={ink} style={inkStyle width height xy}>
+ </span>
+ </xml>)
+ }
+ />
+ </xml>
+end
+
(* TODO(bbaren): Support attributes in the arguments. *)
fun page p = <xml>
<head>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="/material.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -49,63 +88,65 @@ structure Checkbox = struct
style checkbox
style checked
style container
- style ink
(* Pixel dimensions of the checkbox. If you update these, you must also
update the CSS file. *)
val width = 24
val height = 24
- fun centeredAtXY x y : css_style =
- let
- val x' = x - width / 2
- val y' = y - width / 2
- in
- oneProperty (oneProperty
- noStyle
- (value (property "left") (atom (show x' ^ "px"))))
- (value (property "top") (atom (show y' ^ "px")))
- end
-
- fun inkAnimation (s : source (option {X : int, Y : int})) =
- <xml>
- <dyn
- signal={
- v <- signal s;
- return (case v of
- None => <xml></xml>
- | Some xy => <xml>
- <span class={ink} style={centeredAtXY xy.X xy.Y}></span>
- </xml>)
- }
- />
- </xml>
-
val make c onChange =
s <- source c;
inkCenter <- source None;
return (inNewStackingContext <xml>
- {inkAnimation inkCenter}
- <span
- dynClass={
- c <- signal s;
- return (classes checkbox (if c then checked else null))
- }
- onclick={fn click =>
- set inkCenter (Some {X = click.ClientX, Y = click.ClientY});
- c <- get s;
- let
- val c' = not c
- in
- set s c';
- onChange c'
- end
- }
- >
- </span>
+ <div class={container}>
+ {Ripple.inkAnimation width height inkCenter}
+ <span
+ dynClass={
+ c <- signal s;
+ return (classes checkbox (if c then checked else null))
+ }
+ onclick={fn click =>
+ set inkCenter (Some {X = click.ClientX, Y = click.ClientY});
+ c <- get s;
+ let
+ val c' = not c
+ in
+ set s c';
+ onChange c'
+ end
+ }
+ >
+ </span>
+ </div>
</xml>)
end
+structure FloatingActionButton = struct
+ style container
+ style element
+
+ (* Pixel dimensions of the button. If you update these, you must also
+ update the CSS file. *)
+ val width = 56
+ val height = 56
+
+ fun make s =
+ inkCenter <- source None;
+ return <xml>
+ <div class={container}>
+ <button
+ class={element}
+ onclick={fn click =>
+ set inkCenter (Some {X = click.ClientX, Y = click.ClientY})
+ }
+ >
+ {icon s}
+ </button>
+ {Ripple.inkAnimation width height inkCenter}
+ </div>
+ </xml>
+end
+
structure List = struct
structure SingleLine = struct
style element
diff --git a/material/material.urs b/material/material.urs
index cee2b85..7cb7c89 100644
--- a/material/material.urs
+++ b/material/material.urs
@@ -1,4 +1,4 @@
-(* Copyright 2016 Benjamin Barenblat
+(* Copyright 2016, 2017 Benjamin Barenblat
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
@@ -21,6 +21,10 @@ structure Checkbox : sig
val make : bool -> (bool -> transaction unit) -> transaction xbody
end
+structure FloatingActionButton : sig
+ val make : string -> transaction xbody
+end
+
structure List : sig
structure SingleLine : sig
val make : xbody -> xbody