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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -4
  3. data/app/assets/images/marksmith/svgs/bold.svg +1 -1
  4. data/app/assets/images/marksmith/svgs/code.svg +1 -1
  5. data/app/assets/images/marksmith/svgs/color-swatch.svg +1 -1
  6. data/app/assets/images/marksmith/svgs/gallery.svg +1 -1
  7. data/app/assets/images/marksmith/svgs/header.svg +1 -1
  8. data/app/assets/images/marksmith/svgs/image.svg +1 -1
  9. data/app/assets/images/marksmith/svgs/italic.svg +1 -1
  10. data/app/assets/images/marksmith/svgs/link.svg +1 -1
  11. data/app/assets/images/marksmith/svgs/markdown.svg +1 -1
  12. data/app/assets/images/marksmith/svgs/ordered-list.svg +1 -1
  13. data/app/assets/images/marksmith/svgs/paperclip.svg +1 -1
  14. data/app/assets/images/marksmith/svgs/quote.svg +1 -1
  15. data/app/assets/images/marksmith/svgs/task-list.svg +1 -1
  16. data/app/assets/images/marksmith/svgs/unordered-list.svg +1 -1
  17. data/app/assets/javascripts/list_continuation_controller-full.esm.js +1 -1
  18. data/app/assets/javascripts/list_continuation_controller-no-stimulus.esm.js +1 -1
  19. data/app/assets/javascripts/marksmith_controller-full.esm.js +19 -12
  20. data/app/assets/javascripts/marksmith_controller-no-stimulus.esm.js +19 -12
  21. data/app/assets/stylesheets/marksmith.css +171 -29
  22. data/app/frontend/entrypoints/application.css +5 -0
  23. data/app/frontend/entrypoints/javascript/controllers/marksmith_controller.js +18 -11
  24. data/app/helpers/marksmith/marksmith_helper.rb +59 -0
  25. data/app/models/marksmith/editor.rb +104 -0
  26. data/app/models/marksmith/renderer.rb +8 -1
  27. data/app/views/marksmith/shared/_action_bar.html.erb +15 -0
  28. data/app/views/marksmith/shared/_editor.html.erb +10 -114
  29. data/app/views/marksmith/shared/_editor_pane.html.erb +35 -0
  30. data/app/views/marksmith/shared/_loading_indicator.html.erb +4 -0
  31. data/app/views/marksmith/shared/_preview_pane.html.erb +8 -0
  32. data/app/views/marksmith/shared/_rendered_body.html.erb +1 -1
  33. data/app/views/marksmith/shared/_tabs.html.erb +8 -0
  34. data/app/views/marksmith/shared/_toolbar.html.erb +8 -0
  35. data/config/locales/marksmith.de.yml +17 -0
  36. data/lib/marksmith/engine.rb +2 -2
  37. data/lib/marksmith/version.rb +1 -1
  38. metadata +11 -5
  39. data/app/assets/images/marksmith/svgs/color-swatch copy.svg +0 -3
  40. data/app/assets/images/marksmith/svgs/link copy.svg +0 -3
  41. 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', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
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('ms:hidden')
38
- this.previewTabButtonTarget.classList.remove('ms:hidden')
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.previewElementTarget.classList.add('ms:hidden')
44
+ this.previewPaneTarget.classList.add('ms:hidden')
43
45
 
44
46
  // toggle the toolbar back
45
- this.toolbarTarget.classList.remove('ms:hidden')
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.previewElementTarget.id,
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.previewElementTarget.style.minHeight = `${this.fieldElementTarget.offsetHeight}px`
68
+ this.previewPaneTarget.style.minHeight = `${this.fieldElementTarget.offsetHeight}px`
62
69
 
63
70
  // toggle buttons
64
- this.writeTabButtonTarget.classList.remove('ms:hidden')
65
- this.previewTabButtonTarget.classList.add('ms:hidden')
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.previewElementTarget.classList.remove('ms:hidden')
76
+ this.previewPaneTarget.classList.remove('ms:hidden')
70
77
 
71
78
  // toggle the toolbar
72
- this.toolbarTarget.classList.add('ms:hidden')
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('utf-8')
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
- class: "marksmith ms:block ms:flex-col ms:w-full ms:border ms:border-neutral-300 ms:rounded ms:@container ms:focus-within:border-neutral-400",
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
- **local_assigns.fetch(:controller_data_attributes, {})
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
- <% toggle_button_classes = class_names(marksmith_button_classes, "ms:bg-neutral-200 ms:border-0 ms:bg-none ms:text-sm ms:hover:bg-neutral-300 ms:uppercase ms:text-xs ms:font-semibold ms:text-neutral-800") %>
59
- <div class="ms:flex-1 ms:flex-col-reverse ms:@md:flex-row ms:grow ms:flex ms:justify-bewteen ms:bg-neutral-50 ms:rounded ms:px-2 ms:py-1 ms:gap-y-1">
60
- <div class="ms:flex-1 ms:flex ms:items:center">
61
- <button class="<%= toggle_button_classes %>" data-action="click->marksmith#switchToPreview" data-marksmith-target="previewTabButton" type="button">
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,4 @@
1
+ <div class="ms:button-spinner">
2
+ <div class="double-bounce1"></div>
3
+ <div class="double-bounce2"></div>
4
+ </div>
@@ -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
@@ -4,8 +4,8 @@ module Marksmith
4
4
 
5
5
  initializer "marksmith.view_helpers" do
6
6
  ActiveSupport.on_load :action_view do
7
- require "marksmith/helper"
8
- ActionView::Base.include Marksmith::Helper
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)
@@ -1,3 +1,3 @@
1
1
  module Marksmith
2
- VERSION = "0.2.2"
2
+ VERSION = "0.4.0"
3
3
  end
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.2.2
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-02-21 00:00:00.000000000 Z
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>
@@ -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