From 3e39f97d844dbe0ff5f57e3977bc220d366d4c0e Mon Sep 17 00:00:00 2001 From: Joris Date: Sat, 8 Aug 2020 13:41:27 +0200 Subject: Show icons in marker form --- public/main.css | 19 +++- src/Lib/Dom/Element.ml | 9 +- src/Lib/Dom/Event.ml | 3 + src/Lib/Dom/HE.ml | 2 + src/Lib/FontAwesome.ml | 222 +++++++++++++++++++++--------------------- src/View/Form/Autocomplete.ml | 36 ++++--- src/View/Map/Marker.ml | 28 ++++-- 7 files changed, 182 insertions(+), 137 deletions(-) diff --git a/public/main.css b/public/main.css index c57ae2f..c93be65 100644 --- a/public/main.css +++ b/public/main.css @@ -38,8 +38,13 @@ body { margin-bottom: 2rem; } +.g-Layout__Line { + display: flex; + align-items: center; +} + .g-Layout__Line > *:not(:last-child) { - margin-right: 2rem; + margin-right: 1.5rem; } /* Modal */ @@ -83,6 +88,10 @@ body { font-size: 200%; } +.g-Modal__Close:hover { + background-color: #CCCCCC; +} + /* Context menu */ :root { @@ -139,7 +148,6 @@ body { .g-Autocomplete { position: relative; - margin-bottom: 1rem; } .g-Autocomplete__Input { @@ -206,6 +214,13 @@ body { cursor: default; } +/* Marker form */ + +.g-MarkerForm__Icon { + width: 1rem; + border: 1px solid #EEEEEE; +} + /* Marker icon */ :root { diff --git a/src/Lib/Dom/Element.ml b/src/Lib/Dom/Element.ml index 391a95c..3c63ef4 100644 --- a/src/Lib/Dom/Element.ml +++ b/src/Lib/Dom/Element.ml @@ -1,10 +1,15 @@ -external set_value : Dom.element -> string -> unit = "value" [@@bs.set] +external set_value : Dom.element -> string -> unit = "value" + [@@bs.set] -external value : Dom.element -> string = "value" [@@bs.get] +external value : Dom.element -> string = "value" + [@@bs.get] external set_attribute : Dom.element -> string -> string -> unit = "setAttribute" [@@bs.send] +external set_class_name : Dom.element -> string -> unit = "className" + [@@bs.set] + external add_event_listener : Dom.element -> string -> (Dom.event -> unit) -> unit = "addEventListener" [@@bs.send] diff --git a/src/Lib/Dom/Event.ml b/src/Lib/Dom/Event.ml index 861afcf..9db46f0 100644 --- a/src/Lib/Dom/Event.ml +++ b/src/Lib/Dom/Event.ml @@ -1,6 +1,9 @@ external prevent_default : Dom.event -> unit = "preventDefault" [@@bs.send] +external stop_propagation : Dom.event -> unit = "stopPropagation" + [@@bs.send] + external target : Dom.event -> Dom.element = "target" [@@bs.get] diff --git a/src/Lib/Dom/HE.ml b/src/Lib/Dom/HE.ml index 098259a..c9aac16 100644 --- a/src/Lib/Dom/HE.ml +++ b/src/Lib/Dom/HE.ml @@ -5,3 +5,5 @@ let on_click f = H.EventAttr ("click", f) let on_input f = H.EventAttr ("input", f) let on_submit f = H.EventAttr ("submit", f) + +let on_blur f = H.EventAttr ("blur", f) diff --git a/src/Lib/FontAwesome.ml b/src/Lib/FontAwesome.ml index ed8f5d5..daaf954 100644 --- a/src/Lib/FontAwesome.ml +++ b/src/Lib/FontAwesome.ml @@ -43,29 +43,29 @@ let icons = ; "arrows-alt" ; "arrows-h" ; "arrows-v" - ; "asl-interpreting (alias)" + ; "asl-interpreting" ; "assistive-listening-systems" ; "asterisk" ; "at" ; "audio-description" - ; "automobile (alias)" + ; "automobile" ; "backward" ; "balance-scale" ; "ban" ; "bandcamp" - ; "bank (alias)" + ; "bank" ; "bar-chart" - ; "bar-chart-o (alias)" + ; "bar-chart-o" ; "barcode" ; "bars" ; "bath" - ; "bathtub (alias)" - ; "battery (alias)" - ; "battery-0 (alias)" - ; "battery-1 (alias)" - ; "battery-2 (alias)" - ; "battery-3 (alias)" - ; "battery-4 (alias)" + ; "bathtub" + ; "battery" + ; "battery-0" + ; "battery-1" + ; "battery-2" + ; "battery-3" + ; "battery-4" ; "battery-empty" ; "battery-full" ; "battery-half" @@ -84,7 +84,7 @@ let icons = ; "birthday-cake" ; "bitbucket" ; "bitbucket-square" - ; "bitcoin (alias)" + ; "bitcoin" ; "black-tie" ; "blind" ; "bluetooth" @@ -105,7 +105,7 @@ let icons = ; "bullseye" ; "bus" ; "buysellads" - ; "cab (alias)" + ; "cab" ; "calculator" ; "calendar" ; "calendar-check-o" @@ -136,7 +136,7 @@ let icons = ; "cc-stripe" ; "cc-visa" ; "certificate" - ; "chain (alias)" + ; "chain" ; "chain-broken" ; "check" ; "check-circle" @@ -160,11 +160,11 @@ let icons = ; "clipboard" ; "clock-o" ; "clone" - ; "close (alias)" + ; "close" ; "cloud" ; "cloud-download" ; "cloud-upload" - ; "cny (alias)" + ; "cny" ; "code" ; "code-fork" ; "codepen" @@ -183,7 +183,7 @@ let icons = ; "compress" ; "connectdevelop" ; "contao" - ; "copy (alias)" + ; "copy" ; "copyright" ; "creative-commons" ; "credit-card" @@ -193,29 +193,29 @@ let icons = ; "css3" ; "cube" ; "cubes" - ; "cut (alias)" + ; "cut" ; "cutlery" - ; "dashboard (alias)" + ; "dashboard" ; "dashcube" ; "database" ; "deaf" - ; "deafness (alias)" - ; "dedent (alias)" + ; "deafness" + ; "dedent" ; "delicious" ; "desktop" ; "deviantart" ; "diamond" ; "digg" - ; "dollar (alias)" + ; "dollar" ; "dot-circle-o" ; "download" ; "dribbble" - ; "drivers-license (alias)" - ; "drivers-license-o (alias)" + ; "drivers-license" + ; "drivers-license-o" ; "dropbox" ; "drupal" ; "edge" - ; "edit (alias)" + ; "edit" ; "eercast" ; "eject" ; "ellipsis-h" @@ -230,7 +230,7 @@ let icons = ; "eraser" ; "etsy" ; "eur" - ; "euro (alias)" + ; "euro" ; "exchange" ; "exclamation" ; "exclamation-circle" @@ -242,15 +242,15 @@ let icons = ; "eye" ; "eye-slash" ; "eyedropper" - ; "fa (alias)" + ; "fa" ; "facebook" - ; "facebook-f (alias)" + ; "facebook-f" ; "facebook-official" ; "facebook-square" ; "fast-backward" ; "fast-forward" ; "fax" - ; "feed (alias)" + ; "feed" ; "female" ; "fighter-jet" ; "file" @@ -259,18 +259,18 @@ let icons = ; "file-code-o" ; "file-excel-o" ; "file-image-o" - ; "file-movie-o (alias)" + ; "file-movie-o" ; "file-o" ; "file-pdf-o" - ; "file-photo-o (alias)" - ; "file-picture-o (alias)" + ; "file-photo-o" + ; "file-picture-o" ; "file-powerpoint-o" - ; "file-sound-o (alias)" + ; "file-sound-o" ; "file-text" ; "file-text-o" ; "file-video-o" ; "file-word-o" - ; "file-zip-o (alias)" + ; "file-zip-o" ; "files-o" ; "film" ; "filter" @@ -281,7 +281,7 @@ let icons = ; "flag" ; "flag-checkered" ; "flag-o" - ; "flash (alias)" + ; "flash" ; "flask" ; "flickr" ; "floppy-o" @@ -302,9 +302,9 @@ let icons = ; "gamepad" ; "gavel" ; "gbp" - ; "ge (alias)" - ; "gear (alias)" - ; "gears (alias)" + ; "ge" + ; "gear" + ; "gears" ; "genderless" ; "get-pocket" ; "gg" @@ -316,24 +316,24 @@ let icons = ; "github-alt" ; "github-square" ; "gitlab" - ; "gittip (alias)" + ; "gittip" ; "glass" ; "glide" ; "glide-g" ; "globe" ; "google" ; "google-plus" - ; "google-plus-circle (alias)" + ; "google-plus-circle" ; "google-plus-official" ; "google-plus-square" ; "google-wallet" ; "graduation-cap" ; "gratipay" ; "grav" - ; "group (alias)" + ; "group" ; "h-square" ; "hacker-news" - ; "hand-grab-o (alias)" + ; "hand-grab-o" ; "hand-lizard-o" ; "hand-o-down" ; "hand-o-left" @@ -345,9 +345,9 @@ let icons = ; "hand-rock-o" ; "hand-scissors-o" ; "hand-spock-o" - ; "hand-stop-o (alias)" + ; "hand-stop-o" ; "handshake-o" - ; "hard-of-hearing (alias)" + ; "hard-of-hearing" ; "hashtag" ; "hdd-o" ; "header" @@ -358,11 +358,11 @@ let icons = ; "history" ; "home" ; "hospital-o" - ; "hotel (alias)" + ; "hotel" ; "hourglass" - ; "hourglass-1 (alias)" - ; "hourglass-2 (alias)" - ; "hourglass-3 (alias)" + ; "hourglass-1" + ; "hourglass-2" + ; "hourglass-3" ; "hourglass-end" ; "hourglass-half" ; "hourglass-o" @@ -374,7 +374,7 @@ let icons = ; "id-card" ; "id-card-o" ; "ils" - ; "image (alias)" + ; "image" ; "imdb" ; "inbox" ; "indent" @@ -383,9 +383,9 @@ let icons = ; "info-circle" ; "inr" ; "instagram" - ; "institution (alias)" + ; "institution" ; "internet-explorer" - ; "intersex (alias)" + ; "intersex" ; "ioxhost" ; "italic" ; "joomla" @@ -400,14 +400,14 @@ let icons = ; "lastfm-square" ; "leaf" ; "leanpub" - ; "legal (alias)" + ; "legal" ; "lemon-o" ; "level-down" ; "level-up" - ; "life-bouy (alias)" - ; "life-buoy (alias)" + ; "life-bouy" + ; "life-buoy" ; "life-ring" - ; "life-saver (alias)" + ; "life-saver" ; "lightbulb-o" ; "line-chart" ; "link" @@ -428,9 +428,9 @@ let icons = ; "low-vision" ; "magic" ; "magnet" - ; "mail-forward (alias)" - ; "mail-reply (alias)" - ; "mail-reply-all (alias)" + ; "mail-forward" + ; "mail-reply" + ; "mail-reply-all" ; "male" ; "map" ; "map-marker" @@ -458,15 +458,15 @@ let icons = ; "minus-square-o" ; "mixcloud" ; "mobile" - ; "mobile-phone (alias)" + ; "mobile-phone" ; "modx" ; "money" ; "moon-o" - ; "mortar-board (alias)" + ; "mortar-board" ; "motorcycle" ; "mouse-pointer" ; "music" - ; "navicon (alias)" + ; "navicon" ; "neuter" ; "newspaper-o" ; "object-group" @@ -484,7 +484,7 @@ let icons = ; "paper-plane-o" ; "paperclip" ; "paragraph" - ; "paste (alias)" + ; "paste" ; "pause" ; "pause-circle" ; "pause-circle-o" @@ -496,7 +496,7 @@ let icons = ; "percent" ; "phone" ; "phone-square" - ; "photo (alias)" + ; "photo" ; "picture-o" ; "pie-chart" ; "pied-piper" @@ -527,7 +527,7 @@ let icons = ; "quora" ; "quote-left" ; "quote-right" - ; "ra (alias)" + ; "ra" ; "random" ; "ravelry" ; "rebel" @@ -537,44 +537,44 @@ let icons = ; "reddit-square" ; "refresh" ; "registered" - ; "remove (alias)" + ; "remove" ; "renren" - ; "reorder (alias)" + ; "reorder" ; "repeat" ; "reply" ; "reply-all" - ; "resistance (alias)" + ; "resistance" ; "retweet" - ; "rmb (alias)" + ; "rmb" ; "road" ; "rocket" - ; "rotate-left (alias)" - ; "rotate-right (alias)" - ; "rouble (alias)" + ; "rotate-left" + ; "rotate-right" + ; "rouble" ; "rss" ; "rss-square" ; "rub" - ; "ruble (alias)" - ; "rupee (alias)" - ; "s15 (alias)" + ; "ruble" + ; "rupee" + ; "s15" ; "safari" - ; "save (alias)" + ; "save" ; "scissors" ; "scribd" ; "search" ; "search-minus" ; "search-plus" ; "sellsy" - ; "send (alias)" - ; "send-o (alias)" + ; "send" + ; "send-o" ; "server" ; "share" ; "share-alt" ; "share-alt-square" ; "share-square" ; "share-square-o" - ; "shekel (alias)" - ; "sheqel (alias)" + ; "shekel" + ; "sheqel" ; "shield" ; "ship" ; "shirtsinbulk" @@ -586,7 +586,7 @@ let icons = ; "sign-language" ; "sign-out" ; "signal" - ; "signing (alias)" + ; "signing" ; "simplybuilt" ; "sitemap" ; "skyatlas" @@ -599,7 +599,7 @@ let icons = ; "snapchat-ghost" ; "snapchat-square" ; "snowflake-o" - ; "soccer-ball-o (alias)" + ; "soccer-ball-o" ; "sort" ; "sort-alpha-asc" ; "sort-alpha-desc" @@ -607,10 +607,10 @@ let icons = ; "sort-amount-desc" ; "sort-asc" ; "sort-desc" - ; "sort-down (alias)" + ; "sort-down" ; "sort-numeric-asc" ; "sort-numeric-desc" - ; "sort-up (alias)" + ; "sort-up" ; "soundcloud" ; "space-shuttle" ; "spinner" @@ -622,8 +622,8 @@ let icons = ; "stack-overflow" ; "star" ; "star-half" - ; "star-half-empty (alias)" - ; "star-half-full (alias)" + ; "star-half-empty" + ; "star-half-full" ; "star-half-o" ; "star-o" ; "steam" @@ -646,7 +646,7 @@ let icons = ; "sun-o" ; "superpowers" ; "superscript" - ; "support (alias)" + ; "support" ; "table" ; "tablet" ; "tachometer" @@ -664,12 +664,12 @@ let icons = ; "th-large" ; "th-list" ; "themeisle" - ; "thermometer (alias)" - ; "thermometer-0 (alias)" - ; "thermometer-1 (alias)" - ; "thermometer-2 (alias)" - ; "thermometer-3 (alias)" - ; "thermometer-4 (alias)" + ; "thermometer" + ; "thermometer-0" + ; "thermometer-1" + ; "thermometer-2" + ; "thermometer-3" + ; "thermometer-4" ; "thermometer-empty" ; "thermometer-full" ; "thermometer-half" @@ -684,15 +684,15 @@ let icons = ; "times" ; "times-circle" ; "times-circle-o" - ; "times-rectangle (alias)" - ; "times-rectangle-o (alias)" + ; "times-rectangle" + ; "times-rectangle-o" ; "tint" - ; "toggle-down (alias)" - ; "toggle-left (alias)" + ; "toggle-down" + ; "toggle-left" ; "toggle-off" ; "toggle-on" - ; "toggle-right (alias)" - ; "toggle-up (alias)" + ; "toggle-right" + ; "toggle-up" ; "trademark" ; "train" ; "transgender" @@ -708,8 +708,8 @@ let icons = ; "tty" ; "tumblr" ; "tumblr-square" - ; "turkish-lira (alias)" - ; "tv (alias)" + ; "turkish-lira" + ; "tv" ; "twitch" ; "twitter" ; "twitter-square" @@ -718,10 +718,10 @@ let icons = ; "undo" ; "universal-access" ; "university" - ; "unlink (alias)" + ; "unlink" ; "unlock" ; "unlock-alt" - ; "unsorted (alias)" + ; "unsorted" ; "upload" ; "usb" ; "usd" @@ -734,8 +734,8 @@ let icons = ; "user-secret" ; "user-times" ; "users" - ; "vcard (alias)" - ; "vcard-o (alias)" + ; "vcard" + ; "vcard-o" ; "venus" ; "venus-double" ; "venus-mars" @@ -751,8 +751,8 @@ let icons = ; "volume-down" ; "volume-off" ; "volume-up" - ; "warning (alias)" - ; "wechat (alias)" + ; "warning" + ; "wechat" ; "weibo" ; "weixin" ; "whatsapp" @@ -766,7 +766,7 @@ let icons = ; "window-minimize" ; "window-restore" ; "windows" - ; "won (alias)" + ; "won" ; "wordpress" ; "wpbeginner" ; "wpexplorer" @@ -775,12 +775,12 @@ let icons = ; "xing" ; "xing-square" ; "y-combinator" - ; "y-combinator-square (alias)" + ; "y-combinator-square" ; "yahoo" - ; "yc (alias)" - ; "yc-square (alias)" + ; "yc" + ; "yc-square" ; "yelp" - ; "yen (alias)" + ; "yen" ; "yoast" ; "youtube" ; "youtube-play" diff --git a/src/View/Form/Autocomplete.ml b/src/View/Form/Autocomplete.ml index 537316d..324a834 100644 --- a/src/View/Form/Autocomplete.ml +++ b/src/View/Form/Autocomplete.ml @@ -1,11 +1,8 @@ let search s xs = - if s == "" then - [| |] - else - let results = Js.Array.filter (Js.String.includes s) xs in - if Js.Array.length results == 1 && results.(0) == s then [| |] else results + let results = Js.Array.filter (Js.String.includes s) xs in + if Js.Array.length results == 1 && results.(0) == s then [| |] else results -let render_completion on_select entries = +let render_completion render_entry on_select entries = H.div [| HA.class_ "g-Autocomplete__Completion" |] (entries @@ -13,11 +10,14 @@ let render_completion on_select entries = H.button [| HA.class_ "g-Autocomplete__Entry" ; HA.type_ "button" - ; HE.on_click (fun _ -> on_select c) + ; HE.on_click (fun e -> + let () = Event.stop_propagation e in + let () = Event.prevent_default e in + on_select c) |] - [| H.text c |])) + (render_entry c))) -let create id label values on_input attrs = +let create attrs id values render_entry on_input = let completion = H.div [| |] [| |] @@ -26,6 +26,7 @@ let create id label values on_input attrs = let update_completion target value = let entries = search value values in Element.mount_on completion (render_completion + render_entry (fun selected -> let () = Element.set_value target selected in let () = Element.remove_children completion in @@ -33,15 +34,13 @@ let create id label values on_input attrs = entries) in + let hide_completion () = + Element.mount_on completion (H.text "") + in + H.div [| HA.class_ "g-Autocomplete" |] - [| H.div - [| HA.class_ "g-Form__Label" |] - [| H.label - [| HA.for_ id |] - [| H.text label |] - |] - ; H.input + [| H.input (Js.Array.concat [| HA.id id ; HA.class_ "g-Autocomplete__Input" @@ -55,6 +54,11 @@ let create id label values on_input attrs = let value = Element.value target in let () = update_completion target value in on_input value) + ; HE.on_blur (fun _ -> + let _ = Js.Global.setTimeout + (fun _ -> hide_completion ()) + 100 + in ()) |] attrs) [| |] diff --git a/src/View/Map/Marker.ml b/src/View/Map/Marker.ml index 58ec4bd..e793742 100644 --- a/src/View/Map/Marker.ml +++ b/src/View/Map/Marker.ml @@ -20,12 +20,28 @@ let form on_validate init_name init_color init_icon = [| |] [| Form.input "g-MarkerForm__Name" "Name" init_name (fun newName -> name := newName) ; Form.color_input "g-MarkerForm__Color" "Color" init_color (fun newColor -> color := newColor) - ; Autocomplete.create - "g-MarkerForm__Icon" - "Icon" - FontAwesome.icons - (fun newIcon -> let () = Js.log newIcon in icon := newIcon) - [| HA.value init_icon |] + ; H.div + [| HA.class_ "g-Form__Field" |] + [| H.div + [| HA.class_ "g-Form__Label" |] + [| H.label + [| HA.for_ "g-MarkerForm__IconInput" |] + [| H.text "Icon" |] + |] + ; let dom_icon = H.div [| HA.class_ ("fa fa-" ^ !icon) |] [| |] in + Layout.line + [| |] + [| H.div [| HA.class_ "g-MarkerForm__Icon" |] [| dom_icon |] + ; Autocomplete.create + [| HA.value init_icon |] + "g-MarkerForm__IconInput" + FontAwesome.icons + (fun icon -> [| H.div [| HA.class_ ("fa fa-" ^ icon) |] [| |] ; H.text icon |]) + (fun newIcon -> + let () = icon := newIcon in + Element.set_class_name dom_icon ("fa fa-" ^ newIcon)) + |] + |] |] ; Layout.line [| |] -- cgit v1.2.3