Merge branch 'simplemde' into 'master'
feat: Add simplemde for editing posts and pages See merge request mythic-insight/legendary!17
This commit is contained in:
		
						commit
						a809fd5ffa
					
				
					 12 changed files with 209 additions and 13 deletions
				
			
		
							
								
								
									
										15
									
								
								apps/admin/lib/kaffy/editor_extension.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								apps/admin/lib/kaffy/editor_extension.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					defmodule Admin.Kaffy.EditorExtension do
 | 
				
			||||||
 | 
					  def stylesheets(_conn) do
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      {:safe, ~s(<link rel="stylesheet" href="/js/css/content-editor.css" />)},
 | 
				
			||||||
 | 
					      {:safe, ~s(<link rel="stylesheet" href="/css/app.css" />)},
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def javascripts(_conn) do
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					      {:safe, ~s(<script src="/js/content-editor.js"></script>)},
 | 
				
			||||||
 | 
					      {:safe, ~s(<script src="/js/app.js"></script>)},
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										40
									
								
								apps/content/lib/content/markup_field.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								apps/content/lib/content/markup_field.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					defmodule Content.MarkupField do
 | 
				
			||||||
 | 
					  use Ecto.Type
 | 
				
			||||||
 | 
					  def type, do: :string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import Phoenix.HTML, only: [sigil_E: 2]
 | 
				
			||||||
 | 
					  import Phoenix.HTML.Form, only: [textarea: 3, label: 2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def cast(text) when is_binary(text) do
 | 
				
			||||||
 | 
					    {:ok, text}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def cast(_), do: :error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def load(data) do
 | 
				
			||||||
 | 
					    {:ok, data}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def dump(text) when is_binary(text), do: {:ok, text}
 | 
				
			||||||
 | 
					  def dump(_), do: :error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def render_form(_conn, _changeset, form, field, admin_opts) do
 | 
				
			||||||
 | 
					    rows = Map.get(admin_opts, :rows, 32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~E"""
 | 
				
			||||||
 | 
					    <div class="form-group ">
 | 
				
			||||||
 | 
					      <%= label(form, field) %>
 | 
				
			||||||
 | 
					      <%= textarea(form, field, [class: "form-control", rows: rows, "data-simplemde": true]) %>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def render_index(conn, resource, field, _opts) do
 | 
				
			||||||
 | 
					    case Map.get(resource, field) do
 | 
				
			||||||
 | 
					      nil ->
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      text ->
 | 
				
			||||||
 | 
					        Content.PostsView.process_content(text)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					@ -4,13 +4,13 @@ defmodule Content.Post do
 | 
				
			||||||
  """
 | 
					  """
 | 
				
			||||||
  use Ecto.Schema
 | 
					  use Ecto.Schema
 | 
				
			||||||
  import Ecto.Changeset
 | 
					  import Ecto.Changeset
 | 
				
			||||||
  alias Content.Slugs
 | 
					  alias Content.{MarkupField, Slugs}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @derive {Phoenix.Param, key: :name}
 | 
					  @derive {Phoenix.Param, key: :name}
 | 
				
			||||||
  schema "posts" do
 | 
					  schema "posts" do
 | 
				
			||||||
    field :date, :naive_datetime
 | 
					    field :date, :naive_datetime
 | 
				
			||||||
    field :date_gmt, :naive_datetime
 | 
					    field :date_gmt, :naive_datetime
 | 
				
			||||||
    field :content, :string, default: ""
 | 
					    field :content, MarkupField, default: ""
 | 
				
			||||||
    field :title, :string
 | 
					    field :title, :string
 | 
				
			||||||
    field :excerpt, :string
 | 
					    field :excerpt, :string
 | 
				
			||||||
    field :status, :string
 | 
					    field :status, :string
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										52
									
								
								apps/content/test/content/markup_field_test.exs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								apps/content/test/content/markup_field_test.exs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,52 @@
 | 
				
			||||||
 | 
					defmodule Content.MarkupFieldTest do
 | 
				
			||||||
 | 
					  use Content.DataCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import Content.MarkupField
 | 
				
			||||||
 | 
					  import Phoenix.HTML, only: [safe_to_string: 1]
 | 
				
			||||||
 | 
					  import Phoenix.HTML.Form, only: [form_for: 3]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def form do
 | 
				
			||||||
 | 
					    :example
 | 
				
			||||||
 | 
					    |> form_for(
 | 
				
			||||||
 | 
					      "/example",
 | 
				
			||||||
 | 
					      as: :test_params
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "underlying db type is string" do
 | 
				
			||||||
 | 
					    assert type() == :string
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "cast string to markup field" do
 | 
				
			||||||
 | 
					    assert cast("foo") == {:ok, "foo"}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "cast nonstring to markup field is an error" do
 | 
				
			||||||
 | 
					    assert cast(1) == :error
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "dump string from markup field" do
 | 
				
			||||||
 | 
					    assert dump("baz") == {:ok, "baz"}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "dump nonstring from markup field is error" do
 | 
				
			||||||
 | 
					    assert dump(3) == :error
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "load value" do
 | 
				
			||||||
 | 
					    assert load("bar") == {:ok, "bar"}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "render_form/5 makes a field with a simplemde data attribute" do
 | 
				
			||||||
 | 
					    safe = render_form(nil, nil, form, :boop, %{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert safe_to_string(safe) =~ "data-simplemde"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test "render_index/4 can render markdown" do
 | 
				
			||||||
 | 
					    markup = render_index(nil, %{text: "# Test"}, :text, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert markup =~ "<h1>"
 | 
				
			||||||
 | 
					    assert markup =~ "Test"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										11
									
								
								apps/core/assets/css/content-editor-overrides.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								apps/core/assets/css/content-editor-overrides.css
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					.CodeMirror-fullscreen {
 | 
				
			||||||
 | 
					  z-index: 1040;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.editor-toolbar.fullscreen {
 | 
				
			||||||
 | 
					  z-index: 1040;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.editor-preview-active-side {
 | 
				
			||||||
 | 
					  z-index: 1040;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,14 +14,7 @@ import "../css/app.scss"
 | 
				
			||||||
//     import socket from "./socket"
 | 
					//     import socket from "./socket"
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
import "phoenix_html"
 | 
					import "phoenix_html"
 | 
				
			||||||
 | 
					import { ready } from "./utils"
 | 
				
			||||||
function ready(fn) {
 | 
					 | 
				
			||||||
  if (document.readyState != 'loading'){
 | 
					 | 
				
			||||||
    fn();
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    document.addEventListener('DOMContentLoaded', fn);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function togglePasswordFieldVisibility()
 | 
					function togglePasswordFieldVisibility()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								apps/core/assets/js/content-editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								apps/core/assets/js/content-editor.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					import { ready } from "./utils"
 | 
				
			||||||
 | 
					import SimpleMDE from "simplemde"
 | 
				
			||||||
 | 
					import "simplemde/dist/simplemde.min.css"
 | 
				
			||||||
 | 
					import "../css/content-editor-overrides.css"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const requestPreview = (plainText, previewContainer) => {
 | 
				
			||||||
 | 
					  let request = new XMLHttpRequest()
 | 
				
			||||||
 | 
					  const postForm = previewContainer.closest('form')
 | 
				
			||||||
 | 
					  let formData = new FormData(postForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  formData.set('post[content]', plainText)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request.addEventListener('load', function(event) {
 | 
				
			||||||
 | 
					    previewContainer.innerHTML = event.target.responseText
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request.open('POST', '/pages/posts/preview', true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request.send(formData)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ready(() => {
 | 
				
			||||||
 | 
					  document.querySelectorAll('[data-simplemde]').forEach(el => {
 | 
				
			||||||
 | 
					    new SimpleMDE({
 | 
				
			||||||
 | 
					      element: el,
 | 
				
			||||||
 | 
					      previewRender: (plainText, previewContainer) => {
 | 
				
			||||||
 | 
					        requestPreview(plainText, previewContainer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return previewContainer.innerHTML
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										10
									
								
								apps/core/assets/js/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								apps/core/assets/js/utils.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ready = (fn) => {
 | 
				
			||||||
 | 
					  if (document.readyState != 'loading') {
 | 
				
			||||||
 | 
					    fn()
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    document.addEventListener('DOMContentLoaded', fn)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { ready }
 | 
				
			||||||
							
								
								
									
										33
									
								
								apps/core/assets/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										33
									
								
								apps/core/assets/package-lock.json
									
									
									
										generated
									
									
									
								
							| 
						 | 
					@ -3117,6 +3117,19 @@
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
 | 
					      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "codemirror": {
 | 
				
			||||||
 | 
					      "version": "5.56.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.56.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-MfKVmYgifXjQpLSgpETuih7A7WTTIsxvKfSLGseTY5+qt0E1UD1wblZGM6WLenORo8sgmf+3X+WTe2WF7mufyw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "codemirror-spell-checker": {
 | 
				
			||||||
 | 
					      "version": "1.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-HGYPkIlIPMtRE7m6nKGcP0mTNx4=",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "typo-js": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "collection-map": {
 | 
					    "collection-map": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
 | 
				
			||||||
| 
						 | 
					@ -8905,6 +8918,11 @@
 | 
				
			||||||
        "object-visit": "^1.0.0"
 | 
					        "object-visit": "^1.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "marked": {
 | 
				
			||||||
 | 
					      "version": "1.1.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "matchdep": {
 | 
					    "matchdep": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
 | 
				
			||||||
| 
						 | 
					@ -11762,6 +11780,16 @@
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "simplemde": {
 | 
				
			||||||
 | 
					      "version": "1.11.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/simplemde/-/simplemde-1.11.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-ojo12XjSxA7wfewAjJLwcNjggOM=",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "codemirror": "*",
 | 
				
			||||||
 | 
					        "codemirror-spell-checker": "*",
 | 
				
			||||||
 | 
					        "marked": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "slash": {
 | 
					    "slash": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
 | 
				
			||||||
| 
						 | 
					@ -12839,6 +12867,11 @@
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
 | 
				
			||||||
      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
 | 
					      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "typo-js": {
 | 
				
			||||||
 | 
					      "version": "1.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-W3kLbx+ML9PBl5Bzso/lTvVxk4BCveSNAtQeht59FEtxCdGThmn6wSHA4Xq3eQYAK24NHdisMM4JmsK0GFy/pg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "uglify-js": {
 | 
					    "uglify-js": {
 | 
				
			||||||
      "version": "2.8.29",
 | 
					      "version": "2.8.29",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,8 @@
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "gulp": "^4.0.2",
 | 
					    "gulp": "^4.0.2",
 | 
				
			||||||
    "phoenix": "file:../deps/phoenix",
 | 
					    "phoenix": "file:../deps/phoenix",
 | 
				
			||||||
    "phoenix_html": "file:../deps/phoenix_html"
 | 
					    "phoenix_html": "file:../deps/phoenix_html",
 | 
				
			||||||
 | 
					    "simplemde": "^1.11.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@babel/core": "^7.0.0",
 | 
					    "@babel/core": "^7.0.0",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,8 @@ module.exports = (env, options) => {
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    entry: {
 | 
					    entry: {
 | 
				
			||||||
      'app': glob.sync('./vendor/**/*.js').concat(['./js/app.js'])
 | 
					      'app': glob.sync('./vendor/**/*.js').concat(['./js/app.js']),
 | 
				
			||||||
 | 
					      'content-editor': ['./js/content-editor.js'],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    output: {
 | 
					    output: {
 | 
				
			||||||
      filename: '[name].js',
 | 
					      filename: '[name].js',
 | 
				
			||||||
| 
						 | 
					@ -77,7 +78,10 @@ module.exports = (env, options) => {
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    plugins: [
 | 
					    plugins: [
 | 
				
			||||||
      new MiniCssExtractPlugin({ filename: '../css/app.css' }),
 | 
					      new MiniCssExtractPlugin({
 | 
				
			||||||
 | 
					        filename: 'css/[name].css',
 | 
				
			||||||
 | 
					        chunkFilename: '[id].css',
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
      new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
 | 
					      new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    resolve: {
 | 
					    resolve: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,9 @@ use Mix.Config
 | 
				
			||||||
config :kaffy,
 | 
					config :kaffy,
 | 
				
			||||||
  otp_app: :admin,
 | 
					  otp_app: :admin,
 | 
				
			||||||
  ecto_repo: Admin.Repo,
 | 
					  ecto_repo: Admin.Repo,
 | 
				
			||||||
 | 
					  extensions: [
 | 
				
			||||||
 | 
					    Admin.Kaffy.EditorExtension,
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  router: Admin.Router,
 | 
					  router: Admin.Router,
 | 
				
			||||||
  resources: &Admin.Kaffy.Config.create_resources/1
 | 
					  resources: &Admin.Kaffy.Config.create_resources/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue