Commit 59af3f6f authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[CodeEditor] view type toggle (code/preview/both) + some refactoring

parent a1108e5b
.code-editor { .code-editor .toolbar {
display: flex; display: flex;
justify-content: flex-start;
width: 100%; width: 100%;
} }
.code-editor .code { .code-editor .editor {
width: 40%; display: flex;
width: 100%;
}
.code-editor .editor .code {
flex-grow: 1;
} }
.code-editor .code code { .code-editor .editor .code code {
background-color: #f7f7f9; background-color: #f7f7f9;
color: #000; color: #000;
display: block; display: block;
height: 500px; height: 500px;
} }
.code-editor .html { .code-editor .editor .html {
flex-grow: 2;
margin-left: 25px; margin-left: 25px;
padding-left: 25px; padding-left: 25px;
width: 60%;
} }
.code-editor .html ul li { .code-editor .editor .html ul li {
list-style: disc !important; list-style: disc !important;
} }
.code-editor .html ol li { .code-editor .editor .html ol li {
list-style: decimal !important; list-style: decimal !important;
} }
/*# sourceMappingURL=MarkdownEditor.css.map */ /*# sourceMappingURL=CodeEditor.css.map */
.code-editor
.toolbar
display: flex
justify-content: flex-start
width: 100%
.editor
display: flex
width: 100%
.code
flex-grow: 1
code
background-color: #f7f7f9
color: #000
display: block
height: 500px
.html
flex-grow: 2
margin-left: 25px
padding-left: 25px
ul
li
list-style: disc !important
ol
li
list-style: decimal !important
.code-editor
display: flex
width: 100%
.code
code
background-color: #f7f7f9
color: #000
display: block
height: 500px
width: 40%
.html
margin-left: 25px
padding-left: 25px
width: 60%
ul
li
list-style: disc !important
ol
li
list-style: decimal !important
...@@ -9,7 +9,9 @@ import DOM.Simple.Console (log, log2) ...@@ -9,7 +9,9 @@ import DOM.Simple.Console (log, log2)
import DOM.Simple.Types (Element) import DOM.Simple.Types (Element)
import Effect (Effect) import Effect (Effect)
import FFI.Simple ((.=), delay) import FFI.Simple ((.=), delay)
import Prelude (($), (>>>), Unit, bind, const, discard, identity, pure, unit) import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Eq (genericEq)
import Data.Generic.Rep.Show (genericShow)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Text.Markdown.SlamDown.Parser (parseMd) import Text.Markdown.SlamDown.Parser (parseMd)
...@@ -17,9 +19,22 @@ import Text.Markdown.SlamDown.Smolder as MD ...@@ -17,9 +19,22 @@ import Text.Markdown.SlamDown.Smolder as MD
import Text.Markdown.SlamDown.Syntax (SlamDownP(..)) import Text.Markdown.SlamDown.Syntax (SlamDownP(..))
import Text.Smolder.Renderer.String (render) import Text.Smolder.Renderer.String (render)
import Gargantext.Prelude
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
data CodeType = Markdown data CodeType = JSON | Markdown
derive instance genericCodeType :: Generic CodeType _
instance eqCodeType :: Eq CodeType where
eq = genericEq
instance showCodeType :: Show CodeType where
show = genericShow
data ViewType = Code | Preview | Both
derive instance genericViewType :: Generic ViewType _
instance eqViewType :: Eq ViewType where
eq = genericEq
instance showViewType :: Show ViewType where
show = genericShow
type Props = type Props =
( code :: String ( code :: String
...@@ -27,6 +42,10 @@ type Props = ...@@ -27,6 +42,10 @@ type Props =
, onChange :: String -> Effect Unit , onChange :: String -> Effect Unit
) )
compile :: CodeType -> String -> String
compile JSON code = code
compile Markdown code = compileMd code
compileMd' :: forall e. MD.ToMarkupOptions e -> String -> String compileMd' :: forall e. MD.ToMarkupOptions e -> String -> String
compileMd' options input = compileMd' options input =
either identity (MD.toMarkup' options >>> render) either identity (MD.toMarkup' options >>> render)
...@@ -45,6 +64,8 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt ...@@ -45,6 +64,8 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
htmlRef <- R.useRef null htmlRef <- R.useRef null
codeRef <- R.useRef null codeRef <- R.useRef null
editorCodeRef <- R.useRef code editorCodeRef <- R.useRef code
codeTypeS <- R.useState' codeType
viewType <- R.useState' Both
-- Note: delay is necessary here, otherwise initially the HTML won't get -- Note: delay is necessary here, otherwise initially the HTML won't get
-- rendered (mDiv is still null) -- rendered (mDiv is still null)
...@@ -53,7 +74,7 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt ...@@ -53,7 +74,7 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
case mHtmlEl of case mHtmlEl of
Nothing -> pure $ pure unit Nothing -> pure $ pure unit
Just htmlEl -> do Just htmlEl -> do
_ <- pure $ (htmlEl .= "innerHTML") $ compileMd code _ <- pure $ (htmlEl .= "innerHTML") $ compile codeType code
pure $ pure unit pure $ pure unit
R.useEffectOnce $ delay unit $ \_ -> do R.useEffectOnce $ delay unit $ \_ -> do
...@@ -65,20 +86,39 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt ...@@ -65,20 +86,39 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
pure $ pure unit pure $ pure unit
pure $ H.div { className: "code-editor" } [ pure $ H.div { className: "code-editor" } [
H.div { className: "code" } [ H.div { className: "row toolbar" } [
codeTypeSelector {codeType: codeTypeS}
, H.div { className: "btn-group" } [
viewTypeButton {viewType: Code, state: viewType}
, viewTypeButton {viewType: Both, state: viewType}
, viewTypeButton {viewType: Preview, state: viewType}
]
]
, H.div { className: "row editor" } [
H.div { className: "code " <> (codeHidden $ fst viewType) } [
H.code { className: "" H.code { className: ""
, contentEditable: "true" , contentEditable: "true"
, ref: codeRef , ref: codeRef
, rows: 30 , rows: 30
, on: { change: onEditChange codeRef htmlRef editorCodeRef , on: { input: onEditChange codeType codeRef htmlRef editorCodeRef }
, input: onEditChange codeRef htmlRef editorCodeRef }
} [] } []
] ]
, H.div { ref: htmlRef, className: "html" } [] , H.div { ref: htmlRef, className: "html " <> (previewHidden $ fst viewType) } []
] ]
]
codeHidden :: ViewType -> String
codeHidden Code = ""
codeHidden Both = ""
codeHidden _ = "hidden"
previewHidden :: ViewType -> String
previewHidden Preview = ""
previewHidden Both = ""
previewHidden _ = "hidden"
onEditChange :: forall e. R.Ref (Nullable Element) -> R.Ref (Nullable Element) -> R.Ref String -> e -> Effect Unit onEditChange :: forall e. CodeType -> R.Ref (Nullable Element) -> R.Ref (Nullable Element) -> R.Ref String -> e -> Effect Unit
onEditChange codeRef htmlRef editorCodeRef e = do onEditChange codeType codeRef htmlRef editorCodeRef e = do
log2 "[onChange] e" e log2 "[onChange] e" e
let mCode = toMaybe $ R.readRef codeRef let mCode = toMaybe $ R.readRef codeRef
case mCode of case mCode of
...@@ -90,6 +130,65 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt ...@@ -90,6 +130,65 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
case mHtml of case mHtml of
Nothing -> pure unit Nothing -> pure unit
Just html -> do Just html -> do
_ <- pure $ (html .= "innerHTML") $ compileMd $ R.readRef editorCodeRef _ <- pure $ (html .= "innerHTML") $ compile codeType $ R.readRef editorCodeRef
pure unit pure unit
pure unit pure unit
type CodeTypeSelectorProps =
(
codeType :: R.State CodeType
)
codeTypeSelector :: Record CodeTypeSelectorProps -> R.Element
codeTypeSelector p = R.createElement codeTypeSelectorCpt p []
codeTypeSelectorCpt :: R.Component CodeTypeSelectorProps
codeTypeSelectorCpt = R.hooksComponent "G.C.CodeTypeSelector" cpt
where
cpt {codeType} _ = do
pure $ R2.select { className: "form-control"
, on: { change: onSelectChange codeType }
, style: { width: "150px" }
, value: show $ fst codeType }
(option <$> [JSON, Markdown])
option :: CodeType -> R.Element
option value = H.option { value: show value } [ H.text $ show value ]
onSelectChange (_ /\ setCodeType) e = do
let codeType = case value of
"JSON" -> JSON
"Markdown" -> Markdown
_ -> Markdown
setCodeType $ const codeType
where
value = R2.unsafeEventValue e
type ViewTypeProps =
(
viewType :: ViewType
, state :: R.State ViewType
)
viewTypeButton :: Record ViewTypeProps -> R.Element
viewTypeButton p = R.createElement viewTypeButtonCpt p []
viewTypeButtonCpt :: R.Component ViewTypeProps
viewTypeButtonCpt = R.hooksComponent "G.C.ViewTypeButton" cpt
where
cpt {viewType, state: (state /\ setState)} _ =
pure $ H.label {
className: "btn btn-default" <> (active viewType state)
, on: { click: onClick viewType setState }
} [
H.i { className: "glyphicon " <> (icon viewType) } []
]
active viewType state = if viewType == state then " active" else ""
icon Preview = "glyphicon-eye-open"
icon Both = "glyphicon-transfer"
icon Code = "glyphicon-pencil"
onClick viewType setState _ = setState $ const viewType
...@@ -9,12 +9,13 @@ import Effect.Aff (Aff, throwError) ...@@ -9,12 +9,13 @@ import Effect.Aff (Aff, throwError)
import Effect.Exception (error) import Effect.Exception (error)
import Reactix as R import Reactix as R
import Reactix.DOM.HTML as H import Reactix.DOM.HTML as H
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Components.CodeEditor as CE import Gargantext.Components.CodeEditor as CE
import Gargantext.Components.Node (NodePoly(..), HyperdataList) import Gargantext.Components.Node (NodePoly(..), HyperdataList)
import Gargantext.Types (NodeType(..), AffTableResult)
import Gargantext.Routes (SessionRoute(NodeAPI, Children)) import Gargantext.Routes (SessionRoute(NodeAPI, Children))
import Gargantext.Sessions (Session, get) import Gargantext.Sessions (Session, get)
import Gargantext.Types (NodeType(..), AffTableResult)
type Props = ( nodeId :: Int ) type Props = ( nodeId :: Int )
...@@ -22,15 +23,15 @@ corpusLayout :: Record Props -> R.Element ...@@ -22,15 +23,15 @@ corpusLayout :: Record Props -> R.Element
corpusLayout props = R.createElement corpusLayoutCpt props [] corpusLayout props = R.createElement corpusLayoutCpt props []
corpusLayoutCpt :: R.Component Props corpusLayoutCpt :: R.Component Props
corpusLayoutCpt = R.staticComponent "G.P.Corpus.corpusLayout" cpt corpusLayoutCpt = R.hooksComponent "G.P.Corpus.corpusLayout" cpt
where where
cpt {nodeId} _ = cpt {nodeId} _ = do
H.div {} pure $ H.div {}
[ [
CE.codeEditor {code, codeType: CE.Markdown, onChange} CE.codeEditor {code, codeType: CE.Markdown, onChange}
--H.iframe { src: gargMd , width: "100%", height: "100%", style: {"border-style": "none"}} [] --H.iframe { src: gargMd , width: "100%", height: "100%", style: {"border-style": "none"}} []
] ]
gargMd = "https://hackmd.iscpif.fr/g9Aah4iwQtCayIzsKQjA0Q#" --gargMd = "https://hackmd.iscpif.fr/g9Aah4iwQtCayIzsKQjA0Q#"
code = "# Hello world\n\n## subtitle\n\n- item 1\n- item 2\n\n1. num 1\n2. num 2\n\n[purescript link](https://purescript.org)" code = "# Hello world\n\n## subtitle\n\n- item 1\n- item 2\n\n1. num 1\n2. num 2\n\n[purescript link](https://purescript.org)"
onChange c = do onChange c = do
log2 "[corpusLayoutCpt] c" c log2 "[corpusLayoutCpt] c" c
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<link rel="stylesheet" type="text/css" href="styles/menu.css"/> <link rel="stylesheet" type="text/css" href="styles/menu.css"/>
<link href="styles/Graph.css" rel="stylesheet" type="text/css" /> <link href="styles/Graph.css" rel="stylesheet" type="text/css" />
<link href="styles/Login.css" rel="stylesheet" type="text/css" /> <link href="styles/Login.css" rel="stylesheet" type="text/css" />
<link href="styles/MarkdownEditor.css" rel="stylesheet" type="text/css" /> <link href="styles/CodeEditor.css" rel="stylesheet" type="text/css" />
<link href="styles/range-slider.css" rel="stylesheet" type="text/css" /> <link href="styles/range-slider.css" rel="stylesheet" type="text/css" />
<style> <style>
* {margin: 0; padding: 0; list-style: none;} * {margin: 0; padding: 0; list-style: none;}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment