marksmith 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -4
- data/app/assets/images/marksmith/svgs/bold.svg +1 -1
- data/app/assets/images/marksmith/svgs/code.svg +1 -1
- data/app/assets/images/marksmith/svgs/color-swatch.svg +1 -1
- data/app/assets/images/marksmith/svgs/gallery.svg +1 -1
- data/app/assets/images/marksmith/svgs/header.svg +1 -1
- data/app/assets/images/marksmith/svgs/image.svg +1 -1
- data/app/assets/images/marksmith/svgs/italic.svg +1 -1
- data/app/assets/images/marksmith/svgs/link.svg +1 -1
- data/app/assets/images/marksmith/svgs/markdown.svg +1 -1
- data/app/assets/images/marksmith/svgs/ordered-list.svg +1 -1
- data/app/assets/images/marksmith/svgs/paperclip.svg +1 -1
- data/app/assets/images/marksmith/svgs/quote.svg +1 -1
- data/app/assets/images/marksmith/svgs/task-list.svg +1 -1
- data/app/assets/images/marksmith/svgs/unordered-list.svg +1 -1
- data/app/assets/javascripts/list_continuation_controller-full.esm.js +1 -1
- data/app/assets/javascripts/list_continuation_controller-no-stimulus.esm.js +1 -1
- data/app/assets/javascripts/marksmith_controller-full.esm.js +19 -12
- data/app/assets/javascripts/marksmith_controller-no-stimulus.esm.js +19 -12
- data/app/assets/stylesheets/marksmith.css +171 -29
- data/app/frontend/entrypoints/application.css +5 -0
- data/app/frontend/entrypoints/javascript/controllers/marksmith_controller.js +18 -11
- data/app/helpers/marksmith/marksmith_helper.rb +59 -0
- data/app/models/marksmith/editor.rb +104 -0
- data/app/models/marksmith/renderer.rb +8 -1
- data/app/views/marksmith/shared/_action_bar.html.erb +15 -0
- data/app/views/marksmith/shared/_editor.html.erb +10 -114
- data/app/views/marksmith/shared/_editor_pane.html.erb +35 -0
- data/app/views/marksmith/shared/_loading_indicator.html.erb +4 -0
- data/app/views/marksmith/shared/_preview_pane.html.erb +8 -0
- data/app/views/marksmith/shared/_rendered_body.html.erb +1 -1
- data/app/views/marksmith/shared/_tabs.html.erb +8 -0
- data/app/views/marksmith/shared/_toolbar.html.erb +8 -0
- data/config/locales/marksmith.de.yml +17 -0
- data/lib/marksmith/engine.rb +2 -2
- data/lib/marksmith/version.rb +1 -1
- metadata +11 -5
- data/app/assets/images/marksmith/svgs/color-swatch copy.svg +0 -3
- data/app/assets/images/marksmith/svgs/link copy.svg +0 -3
- data/lib/marksmith/helper.rb +0 -29
@@ -20,7 +20,9 @@ export default class extends Controller {
|
|
20
20
|
fileUploadsEnabled: { type: Boolean, default: true },
|
21
21
|
}
|
22
22
|
|
23
|
-
static targets = ['fieldContainer', 'fieldElement', '
|
23
|
+
static targets = ['fieldContainer', 'fieldElement', 'previewPane', 'writeTabButton', 'previewTabButton', 'toolbar']
|
24
|
+
|
25
|
+
activeTabClass = "active"
|
24
26
|
|
25
27
|
get #fileUploadsDisabled() {
|
26
28
|
return !this.fileUploadsEnabledValue
|
@@ -34,42 +36,47 @@ export default class extends Controller {
|
|
34
36
|
event.preventDefault()
|
35
37
|
|
36
38
|
// toggle buttons
|
37
|
-
this.writeTabButtonTarget.classList.add(
|
38
|
-
this.previewTabButtonTarget.classList.remove(
|
39
|
+
this.writeTabButtonTarget.classList.add(this.activeTabClass)
|
40
|
+
this.previewTabButtonTarget.classList.remove(this.activeTabClass)
|
39
41
|
|
40
42
|
// toggle write/preview buttons
|
41
43
|
this.fieldContainerTarget.classList.remove('ms:hidden')
|
42
|
-
this.
|
44
|
+
this.previewPaneTarget.classList.add('ms:hidden')
|
43
45
|
|
44
46
|
// toggle the toolbar back
|
45
|
-
this.toolbarTarget.classList.remove('ms:
|
47
|
+
this.toolbarTarget.classList.remove('ms:opacity-0', 'ms:pointer-events-none')
|
46
48
|
}
|
47
49
|
|
48
50
|
switchToPreview(event) {
|
49
51
|
event.preventDefault()
|
50
52
|
|
53
|
+
// unfocus the active element to hide the outline around the editor
|
54
|
+
this.element.focus()
|
55
|
+
this.element.blur()
|
56
|
+
document.activeElement.blur()
|
57
|
+
|
51
58
|
post(this.previewUrlValue, {
|
52
59
|
body: {
|
53
60
|
body: this.fieldElementTarget.value,
|
54
|
-
element_id: this.
|
61
|
+
element_id: this.previewPaneTarget.id,
|
55
62
|
extra_params: this.extraPreviewParamsValue,
|
56
63
|
},
|
57
64
|
responseKind: 'turbo-stream',
|
58
65
|
})
|
59
66
|
|
60
67
|
// set the min height to the field element height
|
61
|
-
this.
|
68
|
+
this.previewPaneTarget.style.minHeight = `${this.fieldElementTarget.offsetHeight}px`
|
62
69
|
|
63
70
|
// toggle buttons
|
64
|
-
this.writeTabButtonTarget.classList.remove(
|
65
|
-
this.previewTabButtonTarget.classList.add(
|
71
|
+
this.writeTabButtonTarget.classList.remove(this.activeTabClass)
|
72
|
+
this.previewTabButtonTarget.classList.add(this.activeTabClass)
|
66
73
|
|
67
74
|
// toggle elements
|
68
75
|
this.fieldContainerTarget.classList.add('ms:hidden')
|
69
|
-
this.
|
76
|
+
this.previewPaneTarget.classList.remove('ms:hidden')
|
70
77
|
|
71
78
|
// toggle the toolbar
|
72
|
-
this.toolbarTarget.classList.add('ms:
|
79
|
+
this.toolbarTarget.classList.add('ms:opacity-0', 'ms:pointer-events-none')
|
73
80
|
}
|
74
81
|
|
75
82
|
dropUpload(event) {
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Marksmith
|
2
|
+
module MarksmithHelper
|
3
|
+
def marksmithed(body)
|
4
|
+
Marksmith::Renderer.new(body:).render
|
5
|
+
end
|
6
|
+
|
7
|
+
def marksmith_tag(name, **kwargs, &block)
|
8
|
+
rails_direct_uploads_url = if defined?(ActiveStorage)
|
9
|
+
main_app.rails_direct_uploads_url
|
10
|
+
end
|
11
|
+
|
12
|
+
editor = Marksmith::Editor.new(name:, rails_direct_uploads_url:, **kwargs, &block)
|
13
|
+
|
14
|
+
render partial: "marksmith/shared/editor", locals: { name: editor.name, editor: }
|
15
|
+
end
|
16
|
+
|
17
|
+
def marksmith_asset_tags(*args, **kwargs)
|
18
|
+
stylesheet_link_tag("marksmith", *args, **kwargs) +
|
19
|
+
javascript_include_tag("marksmith.esm.js", *args, **kwargs)
|
20
|
+
end
|
21
|
+
|
22
|
+
def marksmith_button_classes
|
23
|
+
class_names(
|
24
|
+
"ms:flex ms:items:center ms:cursor-pointer ms:py-1 ms:px-1.5 ms:hover:bg-neutral-200 ms:rounded",
|
25
|
+
"ms:dark:text-neutral-300 ms:dark:hover:bg-neutral-600"
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def marksmith_toolbar_button(name, **kwargs)
|
30
|
+
content_tag "md-#{name}", marksmith_toolbar_svg(name), title: t("marksmith.#{name.to_s.gsub("-", "_")}").humanize, class: marksmith_button_classes
|
31
|
+
end
|
32
|
+
|
33
|
+
def marksmith_tab_classes
|
34
|
+
class_names(
|
35
|
+
# marksmith_button_classes,
|
36
|
+
"marksmith-toggle-button ms:text-sm ms:hover:bg-neutral-300 ms:text-sm ms:font-medium ms:cursor-pointer ms:text-neutral-500 ms:px-3",
|
37
|
+
# borders
|
38
|
+
"ms:bg-transparent ms:hover:bg-transparent",
|
39
|
+
"ms:-my-px ms:-ml-px ms:border ms:border-transparent",
|
40
|
+
"ms:h-[calc(100%+3px)] ms:border-b-none",
|
41
|
+
# "ms:border-b-neutral-00",
|
42
|
+
# active classes
|
43
|
+
"ms:[.active]:bg-neutral-50 ms:[.active]:text-neutral-900 ms:dark:[.active]:text-neutral-300 ms:[.active]:dark:bg-neutral-800 ms:[.active]:dark:border-neutral-500 ms:[.active]:rounded-t-md ms:[.active]:border-neutral-500",
|
44
|
+
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def marksmith_inline_svg(path)
|
49
|
+
File.open(Marksmith::Engine.root.join(path)).read.html_safe
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO: maybe inline svgs in the future
|
53
|
+
def marksmith_toolbar_svg(name)
|
54
|
+
marksmith_inline_svg("app/assets/images/marksmith/svgs/#{name}.svg")
|
55
|
+
rescue
|
56
|
+
"<!-- Failed to load SVG for #{name} -->"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "uri"
|
2
|
+
|
3
|
+
class Marksmith::Editor
|
4
|
+
attr_reader :name,
|
5
|
+
:extra_preview_params,
|
6
|
+
:form,
|
7
|
+
:disabled,
|
8
|
+
:controller_data_attributes,
|
9
|
+
:classes,
|
10
|
+
:data_attributes,
|
11
|
+
:placeholder,
|
12
|
+
:autofocus,
|
13
|
+
:style,
|
14
|
+
:gallery,
|
15
|
+
:kwargs,
|
16
|
+
:id
|
17
|
+
|
18
|
+
def initialize(name:,
|
19
|
+
upload_url: nil,
|
20
|
+
rails_direct_uploads_url: nil,
|
21
|
+
enable_file_uploads: nil,
|
22
|
+
extra_preview_params: {},
|
23
|
+
form: nil,
|
24
|
+
disabled: false,
|
25
|
+
controller_data_attributes: {},
|
26
|
+
classes: nil,
|
27
|
+
data_attributes: {},
|
28
|
+
placeholder: nil,
|
29
|
+
autofocus: false,
|
30
|
+
style: nil,
|
31
|
+
value: nil,
|
32
|
+
id: "marksmith-instance-#{rand(1000..9999)}",
|
33
|
+
gallery: {},
|
34
|
+
**kwargs)
|
35
|
+
@name = name
|
36
|
+
@kwargs = kwargs
|
37
|
+
|
38
|
+
@upload_url = upload_url
|
39
|
+
@rails_direct_uploads_url = rails_direct_uploads_url
|
40
|
+
@enable_file_uploads = enable_file_uploads
|
41
|
+
@extra_preview_params = extra_preview_params
|
42
|
+
@form = form
|
43
|
+
@disabled = disabled
|
44
|
+
@controller_data_attributes = controller_data_attributes
|
45
|
+
@classes = classes
|
46
|
+
@data_attributes = data_attributes
|
47
|
+
@placeholder = placeholder
|
48
|
+
@autofocus = autofocus
|
49
|
+
@style = style
|
50
|
+
@value = value
|
51
|
+
@id = id
|
52
|
+
@gallery = gallery
|
53
|
+
end
|
54
|
+
|
55
|
+
def gallery_enabled
|
56
|
+
gallery.fetch(:enabled, false)
|
57
|
+
end
|
58
|
+
|
59
|
+
def gallery_open_path
|
60
|
+
gallery.fetch(:open_path, nil)
|
61
|
+
end
|
62
|
+
|
63
|
+
def gallery_params
|
64
|
+
gallery.fetch(:params, {})
|
65
|
+
end
|
66
|
+
|
67
|
+
def gallery_turbo_frame
|
68
|
+
gallery.fetch(:turbo_frame, nil)
|
69
|
+
end
|
70
|
+
|
71
|
+
def gallery_full_path
|
72
|
+
if gallery_open_path.present?
|
73
|
+
uri = URI.parse(gallery_open_path)
|
74
|
+
uri.query = [ uri.query, gallery_params.map { |k, v| "#{k}=#{v}" }.join("&") ].compact.join("&")
|
75
|
+
uri.to_s
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def upload_url
|
80
|
+
if @upload_url.present?
|
81
|
+
@upload_url
|
82
|
+
elsif defined?(ActiveStorage)
|
83
|
+
@rails_direct_uploads_url
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def enable_file_uploads
|
88
|
+
if upload_url.blank?
|
89
|
+
false
|
90
|
+
elsif @enable_file_uploads.nil?
|
91
|
+
true
|
92
|
+
else
|
93
|
+
@enable_file_uploads
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def field_name
|
98
|
+
form&.field_name(name) || name
|
99
|
+
end
|
100
|
+
|
101
|
+
def value
|
102
|
+
form&.object&.send(name) || @value || nil
|
103
|
+
end
|
104
|
+
end
|
@@ -7,6 +7,8 @@ module Marksmith
|
|
7
7
|
def render
|
8
8
|
if Marksmith.configuration.parser == "commonmarker"
|
9
9
|
render_commonmarker
|
10
|
+
elsif Marksmith.configuration.parser == "kramdown"
|
11
|
+
render_kramdown
|
10
12
|
else
|
11
13
|
render_redcarpet
|
12
14
|
end
|
@@ -14,7 +16,7 @@ module Marksmith
|
|
14
16
|
|
15
17
|
def render_commonmarker
|
16
18
|
# commonmarker expects an utf-8 encoded string
|
17
|
-
body = @body.to_s.dup.force_encoding(
|
19
|
+
body = @body.to_s.dup.force_encoding("utf-8")
|
18
20
|
Commonmarker.to_html(body)
|
19
21
|
end
|
20
22
|
|
@@ -34,5 +36,10 @@ module Marksmith
|
|
34
36
|
with_toc_data: true
|
35
37
|
).render(@body)
|
36
38
|
end
|
39
|
+
|
40
|
+
def render_kramdown
|
41
|
+
body = @body.to_s.dup.force_encoding("utf-8")
|
42
|
+
Kramdown::Document.new(body).to_html
|
43
|
+
end
|
37
44
|
end
|
38
45
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= tag.markdown_toolbar for: name,
|
2
|
+
class: class_names("ms:flex ms:flex-wrap ms:px-2 ms:py-1", "ms:pointer-events-none": disabled),
|
3
|
+
data: { marksmith_target: "toolbar" } do
|
4
|
+
%>
|
5
|
+
<%= marksmith_toolbar_button "bold" %>
|
6
|
+
<%= marksmith_toolbar_button "header" %>
|
7
|
+
<%= marksmith_toolbar_button "italic" %>
|
8
|
+
<%= marksmith_toolbar_button "quote" %>
|
9
|
+
<%= marksmith_toolbar_button "code" %>
|
10
|
+
<%= marksmith_toolbar_button "link" %>
|
11
|
+
<%= marksmith_toolbar_button "image" %>
|
12
|
+
<%= marksmith_toolbar_button "unordered-list" %>
|
13
|
+
<%= marksmith_toolbar_button "ordered-list" %>
|
14
|
+
<%= marksmith_toolbar_button "task-list" %>
|
15
|
+
<% end %>
|
@@ -1,46 +1,6 @@
|
|
1
|
-
<%
|
2
|
-
data_attributes = local_assigns[:data] || {}
|
3
|
-
disabled = local_assigns[:disabled] || false
|
4
|
-
placeholder = local_assigns[:placeholder] || nil
|
5
|
-
autofocus = local_assigns[:autofocus] || false
|
6
|
-
style = local_assigns[:style] || nil
|
7
|
-
classes = local_assigns[:class] || nil
|
8
|
-
rows = local_assigns[:rows] || 15
|
9
|
-
field_name = form&.field_name(name) || name
|
10
|
-
value = if defined?(form)
|
11
|
-
form.object.send(name)
|
12
|
-
else
|
13
|
-
local_assigns[:value] || nil
|
14
|
-
end
|
15
|
-
extra_preview_params = local_assigns[:extra_preview_params] || {}
|
16
|
-
upload_url = if local_assigns[:upload_url].present?
|
17
|
-
local_assigns[:upload_url]
|
18
|
-
elsif defined?(ActiveStorage)
|
19
|
-
main_app.rails_direct_uploads_url
|
20
|
-
end
|
21
|
-
|
22
|
-
enable_file_uploads = if upload_url.blank?
|
23
|
-
false
|
24
|
-
elsif local_assigns[:enable_file_uploads].nil?
|
25
|
-
true
|
26
|
-
else
|
27
|
-
local_assigns[:enable_file_uploads]
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
# Used by Avo and other adapters to enable the gallery link.
|
32
|
-
gallery_enabled = local_assigns.dig(:gallery, :enabled) || false
|
33
|
-
gallery_open_path = local_assigns.dig(:gallery, :open_path) || nil
|
34
|
-
gallery_params = local_assigns.dig(:gallery, :params) || {}
|
35
|
-
if gallery_open_path.present?
|
36
|
-
gallery_full_path = gallery_open_path + "?" + gallery_params.map { |k,v| "#{k}=#{v}" }.join('&')
|
37
|
-
else
|
38
|
-
gallery_full_path = nil
|
39
|
-
end
|
40
|
-
gallery_turbo_frame = local_assigns.dig(:gallery, :turbo_frame) || nil
|
41
|
-
%>
|
42
1
|
<%= content_tag :div,
|
43
|
-
|
2
|
+
id: editor.id,
|
3
|
+
class: "marksmith ms:block ms:flex-col ms:w-full ms:border ms:border-neutral-500 ms:rounded-md ms:@container ms:focus-within:outline-2 ms:outline-blue-500 ms:-outline-offset-1",
|
44
4
|
data: {
|
45
5
|
controller: "marksmith list-continuation",
|
46
6
|
action: "
|
@@ -49,79 +9,15 @@
|
|
49
9
|
",
|
50
10
|
unique_selector: ".#{@input_id}", # used to pinpoint the exact element in which to insert the attachment
|
51
11
|
marksmith_preview_url_value: marksmith.markdown_previews_path,
|
52
|
-
marksmith_file_uploads_enabled_value: enable_file_uploads,
|
12
|
+
marksmith_file_uploads_enabled_value: editor.enable_file_uploads,
|
53
13
|
marksmith_active_tab_class: "bg-white",
|
54
|
-
marksmith_attach_url_value: upload_url,
|
55
|
-
marksmith_extra_preview_params_value: extra_preview_params.as_json,
|
56
|
-
**
|
14
|
+
marksmith_attach_url_value: editor.upload_url,
|
15
|
+
marksmith_extra_preview_params_value: editor.extra_preview_params.as_json,
|
16
|
+
**editor.controller_data_attributes,
|
57
17
|
} do %>
|
58
|
-
|
59
|
-
<div class="ms:
|
60
|
-
|
61
|
-
|
62
|
-
<%= t('marksmith.preview').humanize %>
|
63
|
-
</button>
|
64
|
-
<button class="<%= toggle_button_classes %> ms:hidden ms:bg-neutral-200" data-action="click->marksmith#switchToWrite" data-marksmith-target="writeTabButton" type="button">
|
65
|
-
<%= t('marksmith.write').humanize %>
|
66
|
-
</button>
|
67
|
-
</div>
|
68
|
-
|
69
|
-
<markdown-toolbar for="<%= name %>" class="<%= class_names("ms:flex ms:flex-wrap", "ms:pointer-events-none": disabled) %>" data-marksmith-target="toolbar">
|
70
|
-
<%= marksmith_toolbar_button "bold" %>
|
71
|
-
<%= marksmith_toolbar_button "header" %>
|
72
|
-
<%= marksmith_toolbar_button "italic" %>
|
73
|
-
<%= marksmith_toolbar_button "quote" %>
|
74
|
-
<%= marksmith_toolbar_button "code" %>
|
75
|
-
<%= marksmith_toolbar_button "link" %>
|
76
|
-
<%= marksmith_toolbar_button "image" %>
|
77
|
-
<%= marksmith_toolbar_button "unordered-list" %>
|
78
|
-
<%= marksmith_toolbar_button "ordered-list" %>
|
79
|
-
<%= marksmith_toolbar_button "task-list" %>
|
80
|
-
</markdown-toolbar>
|
81
|
-
</div>
|
82
|
-
<% toolbar_button_classes = "ms:cursor-pointer ms:hover:bg-neutral-100 ms:px-1 ms:py-px ms:rounded ms:text-sm" %>
|
83
|
-
<div class="ms:border-t ms:w-full ms:border-neutral-300 ms:flex ms:flex-1">
|
84
|
-
<%= content_tag :div, class: "ms:flex ms:flex-1 ms:flex-col ms:size-full", data: { marksmith_target: "fieldContainer" } do %>
|
85
|
-
<%= text_area_tag field_name, value,
|
86
|
-
id: name,
|
87
|
-
class: class_names("ms:flex ms:flex-1 ms:rounded ms:border-none ms:resize-none ms:focus:outline-none ms:font-mono ms:focus:ring-0 ms:leading-normal ms:p-2 ms:text-sm", classes),
|
88
|
-
rows: rows,
|
89
|
-
data: {
|
90
|
-
action: "drop->marksmith#dropUpload paste->marksmith#pasteUpload",
|
91
|
-
marksmith_target: "fieldElement",
|
92
|
-
**data_attributes
|
93
|
-
},
|
94
|
-
disabled:,
|
95
|
-
placeholder:,
|
96
|
-
autofocus:,
|
97
|
-
style:
|
98
|
-
%>
|
99
|
-
<div class="ms:flex ms:flex-1 ms:flex-grow ms:space-x-2 ms:py-1 ms:border-t ms:border-neutral-300 ms:px-2 ms:font-sans ms:text-sm ms:p-2">
|
100
|
-
<%= link_to "https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax", target: "_blank", class: class_names("ms:flex ms:items-center ms:text-neutral-800 ms:no-underline", toolbar_button_classes) do %>
|
101
|
-
<%= image_tag asset_path("marksmith/svgs/markdown.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.markdown_is_supported").humanize %>
|
102
|
-
<% end %>
|
103
|
-
<% if enable_file_uploads %>
|
104
|
-
<%= button_tag data: { action: "click->marksmith#buttonUpload" }, class: class_names("ms:bg-none ms:border-none ms:bg-transparent ms:text-neutral-600 ms:items-center ms:flex", toolbar_button_classes) do %>
|
105
|
-
<%= image_tag asset_path("marksmith/svgs/paperclip.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.upload_files").humanize %>
|
106
|
-
<% end %>
|
107
|
-
<% end %>
|
108
|
-
<% if gallery_enabled %>
|
109
|
-
<%= link_to gallery_full_path, data: { turbo_frame: gallery_turbo_frame }, class: class_names("ms:flex ms:items-center ms:text-neutral-800 ms:no-underline", toolbar_button_classes) do %>
|
110
|
-
<%= image_tag asset_path("marksmith/svgs/gallery.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.attach_from_gallery").humanize %>
|
111
|
-
<% end %>
|
112
|
-
<% end %>
|
113
|
-
</div>
|
114
|
-
<% end %>
|
115
|
-
<%= content_tag :div,
|
116
|
-
class: "ms:hidden ms:markdown-preview ms:size-full ms:flex-1 ms:flex ms:size-full ms:p-2 ms:overflow-auto",
|
117
|
-
id: "markdown-preview-#{name}",
|
118
|
-
data: {
|
119
|
-
marksmith_target: "previewElement",
|
120
|
-
} do %>
|
121
|
-
<div class="ms:button-spinner">
|
122
|
-
<div class="double-bounce1"></div>
|
123
|
-
<div class="double-bounce2"></div>
|
124
|
-
</div>
|
125
|
-
<% end %>
|
18
|
+
<%= render partial: "marksmith/shared/toolbar", locals: { name: editor.name, disabled: editor.disabled } %>
|
19
|
+
<div class="ms:border-t ms:w-full ms:border-neutral-500 ms:flex ms:flex-1">
|
20
|
+
<%= render partial: "marksmith/shared/editor_pane", locals: { editor: } %>
|
21
|
+
<%= render partial: "marksmith/shared/preview_pane", locals: { name: editor.name } %>
|
126
22
|
</div>
|
127
23
|
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%= content_tag :div, class: "ms:flex ms:flex-1 ms:flex-col ms:size-full", data: { marksmith_target: "fieldContainer" } do %>
|
2
|
+
<%= text_area_tag editor.field_name, editor.value,
|
3
|
+
id: editor.name,
|
4
|
+
class: class_names(
|
5
|
+
"ms:flex ms:flex-1 ms:border-none ms:resize-none ms:focus:outline-none ms:font-mono ms:focus:ring-0 ms:leading-normal ms:p-2 ms:text-sm ms:field-sizing-content ms:min-h-60",
|
6
|
+
"ms:dark:bg-neutral-800 ms:dark:text-neutral-200",
|
7
|
+
editor.classes
|
8
|
+
),
|
9
|
+
data: {
|
10
|
+
action: "drop->marksmith#dropUpload paste->marksmith#pasteUpload",
|
11
|
+
marksmith_target: "fieldElement",
|
12
|
+
**editor.data_attributes
|
13
|
+
},
|
14
|
+
disabled: editor.disabled,
|
15
|
+
placeholder: editor.placeholder,
|
16
|
+
autofocus: editor.autofocus,
|
17
|
+
style: editor.style
|
18
|
+
%>
|
19
|
+
<% toolbar_button_classes = "ms:cursor-pointer ms:hover:bg-neutral-200 ms:px-1 ms:py-px ms:rounded ms:text-sm ms:dark:text-neutral-300 ms:dark:hover:bg-neutral-600" %>
|
20
|
+
<div class="ms:flex ms:flex-1 ms:flex-grow ms:space-x-2 ms:py-1 ms:border-t ms:border-neutral-500 ms:px-2 ms:font-sans ms:text-sm ms:p-2 ms:dark:bg-neutral-800 ms:dark:text-neutral-300 ms:rounded-b-md">
|
21
|
+
<%= link_to "https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax", target: "_blank", class: class_names("ms:flex ms:items-center ms:text-neutral-800 ms:no-underline ms:gap-1", toolbar_button_classes) do %>
|
22
|
+
<%= marksmith_inline_svg("app/assets/images/marksmith/svgs/markdown.svg") %> <span><%= t("marksmith.markdown_is_supported").humanize %></span>
|
23
|
+
<% end %>
|
24
|
+
<% if editor.enable_file_uploads %>
|
25
|
+
<%= button_tag data: { action: "click->marksmith#buttonUpload" }, class: class_names("ms:bg-none ms:border-none ms:bg-transparent ms:text-neutral-600 ms:items-center ms:flex ms:gap-1", toolbar_button_classes) do %>
|
26
|
+
<%= marksmith_inline_svg("app/assets/images/marksmith/svgs/paperclip.svg") %> <span><%= t("marksmith.upload_files").humanize %></span>
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
<% if editor.gallery_enabled %>
|
30
|
+
<%= link_to editor.gallery_full_path, data: { turbo_frame: editor.gallery_turbo_frame }, class: class_names("ms:flex ms:items-center ms:text-neutral-800 ms:no-underline ms:gap-1", toolbar_button_classes) do %>
|
31
|
+
<%= marksmith_inline_svg("app/assets/images/marksmith/svgs/gallery.svg") %> <span><%= t("marksmith.attach_from_gallery").humanize %></span>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= content_tag :div,
|
2
|
+
class: "ms:hidden ms:markdown-preview ms:size-full ms:flex-1 ms:flex ms:size-full ms:p-2 ms:overflow-auto ms:bg-white ms:dark:bg-neutral-800 ms:rounded-b-md",
|
3
|
+
id: "markdown-preview-#{name}",
|
4
|
+
data: {
|
5
|
+
marksmith_target: "previewPane",
|
6
|
+
} do %>
|
7
|
+
<%= render partial: "marksmith/shared/loading_indicator" %>
|
8
|
+
<% end %>
|
@@ -1,3 +1,3 @@
|
|
1
|
-
<%= content_tag :div, class: "ms:block ms:w-full ms:prose ms:max-w-none ms:prose-neutral" do %>
|
1
|
+
<%= content_tag :div, class: "ms:block ms:w-full ms:prose ms:max-w-none ms:prose-neutral ms:dark:prose-invert" do %>
|
2
2
|
<%= sanitize(body, tags: %w(table th tr td span) + ActionView::Helpers::SanitizeHelper.sanitizer_vendor.safe_list_sanitizer.allowed_tags.to_a) %>
|
3
3
|
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="ms:flex-1 ms:flex ms:items:center">
|
2
|
+
<button class="<%= marksmith_tab_classes %> active" data-action="click->marksmith#switchToWrite" data-marksmith-target="writeTabButton" type="button">
|
3
|
+
<%= t('marksmith.write').humanize %>
|
4
|
+
</button>
|
5
|
+
<button class="<%= marksmith_tab_classes %>" data-action="click->marksmith#switchToPreview" data-marksmith-target="previewTabButton" type="button">
|
6
|
+
<%= t('marksmith.preview').humanize %>
|
7
|
+
</button>
|
8
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= tag.div class: class_names(
|
2
|
+
"ms:flex-1 ms:flex-col-reverse ms:@md:flex-row ms:grow ms:flex ms:justify-bewteen ms:bg-neutral-50 ms:rounded-t-md ms:gap-y-1",
|
3
|
+
"ms:dark:bg-neutral-700 ms:dark:text-neutral-200"
|
4
|
+
) do %>
|
5
|
+
<%= render partial: "marksmith/shared/tabs" %>
|
6
|
+
|
7
|
+
<%= render partial: "marksmith/shared/action_bar", locals: { name:, disabled: } %>
|
8
|
+
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
de:
|
2
|
+
marksmith:
|
3
|
+
attach_from_gallery: Aus Galerie hinzufügen
|
4
|
+
bold: Fett
|
5
|
+
code: Code
|
6
|
+
header: Überschrift
|
7
|
+
image: Bild
|
8
|
+
italic: Kursiv
|
9
|
+
link: Link
|
10
|
+
markdown_is_supported: Markdown wird unterstützt
|
11
|
+
ordered_list: Nummerierte Liste
|
12
|
+
preview: Voransicht
|
13
|
+
quote: Zitat
|
14
|
+
task_list: TODO Liste
|
15
|
+
unordered_list: Liste
|
16
|
+
upload_files: Dateien uploaden
|
17
|
+
write: Schreiben
|
data/lib/marksmith/engine.rb
CHANGED
@@ -4,8 +4,8 @@ module Marksmith
|
|
4
4
|
|
5
5
|
initializer "marksmith.view_helpers" do
|
6
6
|
ActiveSupport.on_load :action_view do
|
7
|
-
|
8
|
-
ActionView::Base.include Marksmith::
|
7
|
+
require_relative "../../app/helpers/marksmith/marksmith_helper"
|
8
|
+
ActionView::Base.include Marksmith::MarksmithHelper
|
9
9
|
|
10
10
|
module FormBuilderExtensions
|
11
11
|
def marksmith(*args, **kwargs, &block)
|
data/lib/marksmith/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marksmith
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adrian Marin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -37,13 +37,11 @@ files:
|
|
37
37
|
- app/assets/config/marksmith_manifest.js
|
38
38
|
- app/assets/images/marksmith/svgs/bold.svg
|
39
39
|
- app/assets/images/marksmith/svgs/code.svg
|
40
|
-
- app/assets/images/marksmith/svgs/color-swatch copy.svg
|
41
40
|
- app/assets/images/marksmith/svgs/color-swatch.svg
|
42
41
|
- app/assets/images/marksmith/svgs/gallery.svg
|
43
42
|
- app/assets/images/marksmith/svgs/header.svg
|
44
43
|
- app/assets/images/marksmith/svgs/image.svg
|
45
44
|
- app/assets/images/marksmith/svgs/italic.svg
|
46
|
-
- app/assets/images/marksmith/svgs/link copy.svg
|
47
45
|
- app/assets/images/marksmith/svgs/link.svg
|
48
46
|
- app/assets/images/marksmith/svgs/markdown.svg
|
49
47
|
- app/assets/images/marksmith/svgs/ordered-list.svg
|
@@ -70,12 +68,21 @@ files:
|
|
70
68
|
- app/frontend/entrypoints/javascript/controllers/index.js
|
71
69
|
- app/frontend/entrypoints/javascript/controllers/list_continuation_controller.js
|
72
70
|
- app/frontend/entrypoints/javascript/controllers/marksmith_controller.js
|
71
|
+
- app/helpers/marksmith/marksmith_helper.rb
|
73
72
|
- app/models/marksmith/application_record.rb
|
73
|
+
- app/models/marksmith/editor.rb
|
74
74
|
- app/models/marksmith/renderer.rb
|
75
75
|
- app/views/layouts/marksmith/application.html.erb
|
76
76
|
- app/views/marksmith/markdown_previews/create.turbo_stream.erb
|
77
|
+
- app/views/marksmith/shared/_action_bar.html.erb
|
77
78
|
- app/views/marksmith/shared/_editor.html.erb
|
79
|
+
- app/views/marksmith/shared/_editor_pane.html.erb
|
80
|
+
- app/views/marksmith/shared/_loading_indicator.html.erb
|
81
|
+
- app/views/marksmith/shared/_preview_pane.html.erb
|
78
82
|
- app/views/marksmith/shared/_rendered_body.html.erb
|
83
|
+
- app/views/marksmith/shared/_tabs.html.erb
|
84
|
+
- app/views/marksmith/shared/_toolbar.html.erb
|
85
|
+
- config/locales/marksmith.de.yml
|
79
86
|
- config/locales/marksmith.en.yml
|
80
87
|
- config/routes.rb
|
81
88
|
- config/vite.json
|
@@ -85,7 +92,6 @@ files:
|
|
85
92
|
- lib/marksmith/configuration.rb
|
86
93
|
- lib/marksmith/engine.rb
|
87
94
|
- lib/marksmith/fields/markdown_field.rb
|
88
|
-
- lib/marksmith/helper.rb
|
89
95
|
- lib/marksmith/version.rb
|
90
96
|
- lib/tasks/marksmith_tasks.rake
|
91
97
|
homepage: https://github.com/avo-hq/marksmith
|
@@ -1,3 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
|
2
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"/>
|
3
|
-
</svg>
|
@@ -1,3 +0,0 @@
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
|
2
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"/>
|
3
|
-
</svg>
|
data/lib/marksmith/helper.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
module Marksmith
|
2
|
-
module Helper
|
3
|
-
def marksmithed(body)
|
4
|
-
Marksmith::Renderer.new(body:).render
|
5
|
-
end
|
6
|
-
|
7
|
-
def marksmith_tag(name, **kwargs, &block)
|
8
|
-
render partial: "marksmith/shared/editor", locals: { name: name, **kwargs }
|
9
|
-
end
|
10
|
-
|
11
|
-
def marksmith_asset_tags(*args, **kwargs)
|
12
|
-
stylesheet_link_tag("marksmith", *args, **kwargs) +
|
13
|
-
javascript_include_tag("marksmith.esm.js", *args, **kwargs)
|
14
|
-
end
|
15
|
-
|
16
|
-
def marksmith_button_classes
|
17
|
-
class_names("ms:flex ms:items:center ms:cursor-pointer ms:py-1 ms:px-1.5 ms:hover:bg-neutral-200 ms:rounded")
|
18
|
-
end
|
19
|
-
|
20
|
-
def marksmith_toolbar_button(name, **kwargs)
|
21
|
-
content_tag "md-#{name}", marksmith_toolbar_svg(name), title: t("marksmith.#{name.to_s.gsub("-", "_")}").humanize, class: marksmith_button_classes
|
22
|
-
end
|
23
|
-
|
24
|
-
# TODO: maybe inline svgs in the future
|
25
|
-
def marksmith_toolbar_svg(name)
|
26
|
-
image_tag asset_path("marksmith/svgs/#{name}.svg"), class: "ms:inline ms:size-4"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|