Help us understand the problem. What is going on with this article?

とてもたのしいelm-uiで「おなまえシールめーかー」をつくった🎄

どうも、今年の夏に初めてElmをさわったので、記念としてElmアドベントカレンダーに参加しています🎄
普段はサーバーサイドエンジニア兼 ワロタグマの育成を生業としているものです。
今回は、このワロタグマがどうも小さいお子さんにウケが良い(n=1)とのことで、幼稚園においては何かと必須アイテムであった「おなまえシール」のめーかーを作ってみることにしました。
ちなみにコードは こちら です。

成果物

demo.gif
:point_down:
iOS の画像 (4).jpg

最近、お肌を労るために、髪にも顔にも身体にも使えるナチュナルな石鹸 を使い始めました。
これを手を洗うために使われたら辛い(手はキレイキレイで十分やろ)ので、ラベリングするためにつくりました。
つまり、おなまえシールは大人でも意味のある形で使えます。

おなまえシールのつくりかた

  1. おなまえシールめーかーをひらく
  2. おなまえシールをいい感じにデザインする
  3. (よしなにスクショかなんかして)マスキングテープ に印刷する

圧倒的MVP(Minimum Viable Product) 仕様です。
近々、画像に変換する機能もつけたいですね。

おなまえシールめーかーのつくりかた

elm-ui を使ってつくりました。

半年前にElmで くそゲーをつくった時、

:girl: < 「レイアウトとかで時間使いたくないよ〜〜くそゲー作りながらElmの勉強したいだけだもん〜〜でもオシャにしないとやる気下がる〜〜」

となり、その後興味本位でelm-uiをさわってみて、アイディアをサッと形にしたいときはこれでつくるのが良さそうだなと思いました。
CSSが分からなくても、なんならElmが分からなくても(TEAさえ分かれば)、カンタンにUIができる!

ということで、最短でアイディアを具体化していくことを前提として圧倒的そういうノリでelm-uiを紹介していきたいと思います。
(まずはelm-uiでできることの一覧を見たい方は リファレンス を流し読みすることをオススメします。elmのリファレンスは綺麗で読みやすくて好き。)

まずはTEA

type alias Model =
    { name : String }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    let
        { name } =
            model
    in
    case msg of
        InputName n ->
            ( { model | name = n }, Cmd.none )


view : Model -> Html Msg
view model =
   div []
        [ Html.text "タイトル" ]
    -- この辺にOnInputを入れることになりそう

こんな感じで、おなまえを入力するための土台作りをします。

elm-uiでviewをくみたてる

上記のview関数を、elm-uiを使ってリッチにしていきます。
ということはまず我々は、Html Msg 型を返す関数をリファレンスから探す必要がありそうです。

elm-uiを組み込む土台をつくりたい

小さく小さく作っていきましょう。
Html Msg 型を返す関数が欲しいので、リファレンス(Element)にて Html Msgで検索します。

image.png
ありました〜〜〜〜〜〜🎉
elm-uiをいつものコードに組み込むには、これを噛ませてあげれば良いっぽいですね。

そして、この子には Element msg 型とやらを渡せばいいみたいです。
これも検索してみると、っぽいのがありますね。

text は文字列を Element msg にしてくれる、el はなんと div 相当のものだそう。

ということで、このように書いていきます。

view : Model -> Html Msg
view model =
    layout [] <| el [] <| Element.text "おなまえシールめーかー"

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133373332322f33326562376131612d323338352d373539622d656464392d3033633534613334383136372e706e67.png

まずは文字列を表示することができました🎉

要素を好きな位置に配置したい

とりあえずタイトル「おなまえシールめーかー」を真ん中に置きたい。
center と検索してみると、っぽいのがありました🎉

これらはAttribute msg型を返すので、先ほどの el の定義をみてみると、 List (Attribute msg) に入れてあげれば良さそう。

layout [] <| el [ centerX ] <| Element.text "おなまえシールめーかー"

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133373332322f35343936653761612d613465322d336435622d346266362d6436613538633336323333352e706e67.png

真ん中に配置することができました🎉

ここまででもうelm-uiを使いこなすパターンがお分かりいただけたかと思います。
divを積み上げるような感覚でElement msg をつくっていき、
それぞれの要素は List (Attribute msg) というデコレーション箱を持っているので、それらに Attribute msg 型を返すものを「直接」入れていくだけでリッチになっていきます。

複数の要素を配置したい

まだタイトルしか表示できていませんから、ここから複数の要素を表示させていきたいです。
Element msg を複数個配置したいので、 List (Element msg)で検索してみると、

を発見。
これらは複数個の要素を1つの Element msg に束ねてくれるようです。
タイトルとInputを縦に並べたいので、 column を使ってみます。

view : Model -> Html Msg
view model =
    layout [] <|
        column [ centerX ]
            [ el [] <| Element.text "おなまえシールめーかー"
            , el [] <| Element.text "ここにInput"
            ]

image.png

複数個の要素を縦に配置できました!
このように、縦に配置していきたいか、横に配置していきたいかを考えていれば、そんなに頭を使わずともどんどんUIが出来上がっていきます。

次に、rowImage を使って、ワロタちゃん達を横に並べてみました。

image.png

ん、なんか圧倒的に横にずれて見えないワロタちゃんがいる・・・。
そこで、wrappedRowに怪しげな表記を見つけました。

Same as row, but will wrap if it takes up too much horizontal space.

んーこれですね。

image.png

これでめでたく とても可愛いワロタグマみにえもじ が全員表示できました🎉
(お顔とお手手を繋げていくことでコミュニケーションが取れるこのえもじ天才的に可愛いと思いませんか?)

wrappedRowのデコレーション箱に width を入れて幅を指定することで折り返しを実現できました。

view : Model -> Html Msg
view model =
    layout [] <|
        column [ centerX ]
            [ el [] <| Element.text "おなまえシールめーかー"
            , el [] <| Element.text "ここにInput"
            , wrappedRow [ Element.explain Debug.todo, width (px 420) ] <|
                List.map
                    (\i ->
                        el
                            []
                        <|
                            image
                                [ width <| px 50 ]
                                { src = "assets/" ++ String.fromInt i ++ ".PNG"
                                , description = ""
                                }
                    )
                    (List.range 1 21)
            ]

ちなみに、explainを使うと、👆のようなデバッグモードになりデベロッパーツールを開く手間が省けてとても便利です。

ユーザーに入力させたい

Element.Input を見ていきます。
今回は一行テキスト入力フォームが欲しいので、text を使っていきます。

いい感じのフォームが組み込まれました。
image.png

column [ centerX ]
            [ el [] <| Element.text "おなまえシールめーかー"
            , el [] <|
                Element.Input.text
                    [ width (px 400), centerX ]
                    { onChange = \n -> InputName n
                    , text = name
                    , placeholder = Just <| placeholder [] (Element.text "おなまえ")
                    , label = labelHidden "name"
                    }

いい感じにデコレーションする(Attribute msgで遊ぶ)

余白をつくりたい

まずはpadding, margin相当の Padding and Spacing を使っていい感じにしていきます。
しくみはこういう感じです。
image.png

layout [] <|f
        column [ padding 30, spacing 30, centerX ] [ ... ]

image.png

こうすることで、デザインに余白が生まれ、圧迫感が抑えられました。

色をつけたい

背景色をつけたいので、Element.Backgroundを見ていきます。
colorには Color 型を渡す必要があります。
Color 型を返す関数を探すと、結構色々あります。

今回は、

layout [ Element.Background.color (rgba255 223 107 160 100) ] <| ...

という感じで、設定してみました。
ちなみに、自分の色選びのセンスが悪いと途中でなえてくるので、私はいつも
「{ハイブランド名} パリコレ」で検索
して、イケイケコーディネートをスポイトで吸い取ってRGBに変換しています。
今回は「グッチ パリコレ」でいきました。
これで開発中に「なにこの色・・・」とならず、「これは世界的デザイナーが生み出したお色だからオシャレに違いない」と言い聞かせられます。

image.png

どぎついな。

丸をかきたい

丸はElement.Borderの rounded でかけます。

wrappedRowの中身をこうして、いい感じに変身できました。

wrappedRow [ spacing 5, width (px 470) ] <|
                List.map
                    (\i ->
                        el
                            [ rounded 50
                            , padding 5
                            , Element.Background.color white
                            , onClick <| OnClickButton i
                            ]
                        <|
                            image
                                [ width <| px 50
                                , if clickedIndexList |> List.member i then
                                    alpha 0.5

                                  else
                                    alpha 1
                                ]
                                { src = "assets/" ++ String.fromInt i ++ ".PNG"
                                , description = ""
                                }
                    )
                    (List.range 1 21)

image.png

選択すると、半透明になります。
可愛い!可愛いぞ!

ここまででテンションが上がるUIができたので、
あとはmodelとupdateを書いていって、いい感じに「おなまえシール」の完成形を表示する 機能を実装していくだけです!

ちなみに、以前elm-uiを利用して一番感動したのが indexedTable だったのですが、今回はくそゲーオブくそゲーだったために使わずして完成してしまいました。。
Formが可変長だった場合に、tableの中でFormをindexedMapしたいと思うだろう?と先読みしてくれたかのようなテーブルなので「これこれ〜!」感がありました。
またの機会に記事にしよう。

最後に、印刷しよう

好きなワロタキャラを選択し、おなまえを入力して、下に表示された「おなまえシール」を最後に印刷してfinishiですね。

余談of余談ですが、マスキングテープ印刷用紙 は結構使えます。
私のPCもこんな可愛いくなっています :girl:

iOS の画像 (5).jpg

このめーかーを作るきっかけになったワロタ好きなお子さんにも、つくってあげよう〜〜!

それでは、2019年も残り少ないですが、毎日一切れずつシュトーレンを食べて楽しく過ごしましょう🍰良いを年を〜〜🎍

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした