svg.escobar.life

Unnamed repository; edit this file 'description' to name the repository.

commit f62c6cb5683b638662387fbe711f3487f140d381
parent 22809cfba84311ef77dee35c0e0653306a329d6a
Author: Gark Garcia <37553739+GarkGarcia@users.noreply.github.com>
Date:   Fri, 19 Jul 2019 22:35:41 -0300

Started working on a syntax-highlighted editor.

Diffstat:
Melm.json | 4+++-
Msrc/Main.elm | 4++++
Msrc/Types.elm | 16+++++++++++++---
Msrc/View.elm | 35++++++++++++++++++++++++++++++-----
Mstyles.css | 44+++++++++++++++++++++++++++++---------------
5 files changed, 79 insertions(+), 24 deletions(-)
diff --git a/elm.json b/elm.json
@@ -13,10 +13,12 @@
             "elm/http": "2.0.0",
             "elm/json": "1.1.3",
             "elm/regex": "1.0.0",
-            "elm/svg": "1.0.1"
+            "elm/svg": "1.0.1",
+            "pablohirafuji/elm-syntax-highlight": "3.1.0"
         },
         "indirect": {
             "elm/bytes": "1.0.8",
+            "elm/parser": "1.1.0",
             "elm/time": "1.0.0",
             "elm/url": "1.0.0",
             "elm/virtual-dom": "1.0.2"
diff --git a/src/Main.elm b/src/Main.elm
@@ -44,6 +44,9 @@ update msg model =
         Upload upl ->
             upload model upl
 
+        Scroll offset ->
+            ({model | offset = offset}, Cmd.none)
+
 load : Result Http.Error String -> Cmd Msg
 load result =
     case result of
@@ -74,6 +77,7 @@ init =
     , darkMode = False
     , uriEncoder = Maybe.withDefault Regex.never <| Regex.fromString "!|#|\\$|%|&|'|\\(|\\)|\\*|\\+|,|\\/|:|;|=|\\?|@|\\[|\\]"
     , fileName = "example.svg"
+    , offset = { top = 0, left = 0 }
     }
 
 loadExample : Cmd Msg
diff --git a/src/Types.elm b/src/Types.elm
@@ -5,14 +5,24 @@ import Regex exposing (Regex)
 import Http
 
 type alias Model =
-    { image : String, isValid : Bool, darkMode : Bool, uriEncoder : Regex, fileName : String }
+    { image : String
+    , isValid : Bool
+    , darkMode : Bool
+    , uriEncoder : Regex
+    , fileName : String
+    , offset : Offset
+    }
 
 type Upload = Requested | Selected File
 
+type alias Offset =
+    { top : Int, left : Int }
+
 type Msg
     = Update String
     | Load (Result Http.Error String)
     | Validation Bool
     | DarkModeToggle
     | Download
-    | Upload Upload-
\ No newline at end of file
+    | Upload Upload
+    | Scroll Offset+
\ No newline at end of file
diff --git a/src/View.elm b/src/View.elm
@@ -1,14 +1,15 @@
 module View exposing (view)
 
 import Types exposing (..)
-import Html exposing (Html, div, img, button, a, textarea)
+import Html exposing (Html, div, img, button, a, textarea, pre, code, text)
 import Html.Events exposing (onClick, onInput, on)
-import Html.Attributes exposing (id, class, src, href, value, spellcheck, placeholder, target, rel)
+import Html.Attributes exposing (id, class, src, href, value, style, spellcheck, placeholder, target, rel)
 import Browser exposing (Document)
 import Svg exposing (svg, path)
 import Svg.Attributes exposing (d, viewBox, fill)
 import Json.Decode
 import Regex exposing (Regex, Match, replace)
+import SyntaxHighlight exposing (useTheme, xml, oneDark, toBlockHtml)
 
 
 view : Model -> Document Msg
@@ -41,11 +42,35 @@ display model =
 
 texteditor : Model -> Html Msg
 texteditor model =
-    textarea 
+    div [ id "editor", onInput Update ]
+        [ useTheme oneDark
+        , xml (model.image ++ (String.fromInt model.offset.left))
+            |> Result.map (toBlockHtml Nothing)
+            |> Result.withDefault
+                (pre (translate model.offset)
+                    [ code [] [ text model.image ]]
+                )
+        , viewTextarea model
+        ]
+
+translate : Offset -> List (Html.Attribute Msg)
+translate { top, left } =
+    [ style "left" ((String.fromInt -top) ++ "px")
+    , style "top"  ((String.fromInt -left) ++ "px")
+    ]
+
+viewTextarea : Model -> Html Msg
+viewTextarea model =
+    textarea
         [ value model.image
-        , placeholder "<svg ...> ... </svg>"
+        , onInput Update
         , spellcheck False
-        , onInput (\input -> Update input)
+        , on "scroll"
+            (Json.Decode.map2 Offset
+                (Json.Decode.at [ "target", "scrollTop" ] Json.Decode.int)
+                (Json.Decode.at [ "target", "scrollLeft" ] Json.Decode.int)
+                |> Json.Decode.map Scroll
+            )
         ] []
 
 uri : Model -> String
diff --git a/styles.css b/styles.css
@@ -4,7 +4,6 @@
     align-self: center;
     align-content: center;
     align-items: center;
-    text-align: center;
     
     cursor: default;
     -webkit-user-select: none; /* Safari */        
@@ -26,6 +25,8 @@
         --large: 10vmax;
         --small: 2.5vmax;
         --tiny: 1vmax;
+
+        font-size: .175in;
     }
 }
 
@@ -34,6 +35,8 @@
         --large: 15vmax;
         --small: 3vmax;
         --tiny: 2vmax;
+
+        font-size: .25in;
     }
 }
 
@@ -235,8 +238,31 @@ body > div#container.error > div#display > svg#error {
     display: block;
 }
 
-body > div#container > textarea {
+body > div#container > div#editor {
     grid-area: text;
+    position: relative;
+
+    width: 100%;
+    height: 100%;
+
+    overflow: hidden;
+}
+
+body > div#container > div#editor * {
+    background: transparent !important;
+
+    font-family: 'B612 Mono', monospace !important;
+    font-style: italic !important;
+}
+
+body > div#container > div#editor > * {
+    position: absolute;
+    margin: 0 !important;
+}
+
+body > div#container > div#editor > textarea {
+    z-index: 1;
+
     resize: none;
     white-space: pre;
 
@@ -250,21 +276,9 @@ body > div#container > textarea {
     
 
     font-family: 'B612 Mono', monospace;
-    color: var(--light);
+    color: transparent;
     font-style: italic;
 
     scrollbar-width: none; /*For Firefox*/
     -ms-overflow-style: none; /*For IE and Edge*/
-}
-
-@media (hover: hover) {
-    body > div#container > textarea {
-        font-size: .175in;
-    }
-}
-
-@media (hover: none) {
-    body > div#container > textarea {
-        font-size: .25in;
-    }
 } 
\ No newline at end of file