marksmith 0.0.13 → 0.0.16
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 +32 -20
- data/app/assets/config/marksmith_manifest.js +1 -0
- data/app/assets/images/marksmith/svgs/gallery.svg +1 -0
- data/app/assets/images/marksmith/svgs/markdown.svg +1 -1
- data/app/assets/images/marksmith/svgs/paperclip.svg +1 -1
- data/app/assets/javascripts/list_continuation_controller-full.esm.js +592 -0
- data/app/assets/javascripts/list_continuation_controller-no-stimulus.esm.js +102 -0
- data/app/assets/javascripts/marksmith_controller-full.esm.js +2959 -0
- data/app/assets/javascripts/marksmith_controller-no-stimulus.esm.js +2469 -0
- data/app/assets/stylesheets/marksmith.css +5 -5
- data/app/components/marksmith/markdown_field/edit_component.html.erb +22 -0
- data/app/components/marksmith/markdown_field/edit_component.rb +7 -0
- data/app/components/marksmith/markdown_field/show_component.html.erb +3 -0
- data/app/components/marksmith/markdown_field/show_component.rb +4 -0
- data/app/frontend/entrypoints/javascript/controllers/marksmith_controller.js +35 -15
- data/app/views/marksmith/shared/_editor.html.erb +21 -3
- data/config/locales/marksmith.en.yml +2 -1
- data/lib/marksmith/engine.rb +25 -0
- data/lib/marksmith/fields/markdown_field.rb +15 -0
- data/lib/marksmith/version.rb +1 -1
- metadata +13 -3
@@ -1,5 +1,5 @@
|
|
1
|
-
/*! tailwindcss v4.0.
|
2
|
-
:root {
|
1
|
+
/*! tailwindcss v4.0.1 | MIT License | https://tailwindcss.com */
|
2
|
+
:root, :host {
|
3
3
|
--ms-font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
4
4
|
'Segoe UI Symbol', 'Noto Color Emoji';
|
5
5
|
--ms-font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
@@ -788,6 +788,9 @@
|
|
788
788
|
margin-bottom: 0;
|
789
789
|
}
|
790
790
|
}
|
791
|
+
.ms\:mr-1 {
|
792
|
+
margin-right: calc(var(--ms-spacing) * 1);
|
793
|
+
}
|
791
794
|
.ms\:block {
|
792
795
|
display: block;
|
793
796
|
}
|
@@ -841,9 +844,6 @@
|
|
841
844
|
.ms\:items-center {
|
842
845
|
align-items: center;
|
843
846
|
}
|
844
|
-
.ms\:gap-x-2 {
|
845
|
-
column-gap: calc(var(--ms-spacing) * 2);
|
846
|
-
}
|
847
847
|
.ms\:gap-y-1 {
|
848
848
|
row-gap: calc(var(--ms-spacing) * 1);
|
849
849
|
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%= field_wrapper **field_wrapper_args, full_width: true do %>
|
2
|
+
<%= @form.marksmith @field.id,
|
3
|
+
gallery: {
|
4
|
+
enabled: true,
|
5
|
+
open_path: avo.attach_media_path,
|
6
|
+
turbo_frame: ::Avo::MODAL_FRAME_ID,
|
7
|
+
params: {
|
8
|
+
resource_name: @resource.singular_route_key,
|
9
|
+
controller_name: "marksmith",
|
10
|
+
controller_selector: "[data-unique-selector='#{unique_id}']",
|
11
|
+
record_id: @resource&.record&.to_param,
|
12
|
+
}
|
13
|
+
},
|
14
|
+
controller_data_attributes: {
|
15
|
+
unique_selector: unique_id, # it must coincide with the selector above
|
16
|
+
},
|
17
|
+
extra_preview_params: {
|
18
|
+
resource_class: @resource.class.name,
|
19
|
+
field_id: field.id,
|
20
|
+
}
|
21
|
+
%>
|
22
|
+
<% end %>
|
@@ -15,6 +15,8 @@ export default class extends Controller {
|
|
15
15
|
previewUrl: String,
|
16
16
|
extraPreviewParams: { type: Object, default: {} },
|
17
17
|
fieldId: String,
|
18
|
+
galleryEnabled: { type: Boolean, default: false },
|
19
|
+
galleryOpenPath: String,
|
18
20
|
}
|
19
21
|
|
20
22
|
static targets = ['fieldContainer', 'fieldElement', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
|
@@ -67,14 +69,14 @@ export default class extends Controller {
|
|
67
69
|
|
68
70
|
dropUpload(event) {
|
69
71
|
event.preventDefault()
|
70
|
-
this
|
72
|
+
this.#uploadFiles(event.dataTransfer.files)
|
71
73
|
}
|
72
74
|
|
73
75
|
pasteUpload(event) {
|
74
76
|
if (!event.clipboardData.files.length) return
|
75
77
|
|
76
78
|
event.preventDefault()
|
77
|
-
this
|
79
|
+
this.#uploadFiles(event.clipboardData.files)
|
78
80
|
}
|
79
81
|
|
80
82
|
buttonUpload(event) {
|
@@ -86,40 +88,58 @@ export default class extends Controller {
|
|
86
88
|
fileInput.accept = 'image/*,.pdf,.doc,.docx,.txt'
|
87
89
|
|
88
90
|
fileInput.addEventListener('change', (e) => {
|
89
|
-
this
|
91
|
+
this.#uploadFiles(e.target.files)
|
90
92
|
})
|
91
93
|
|
92
94
|
fileInput.click()
|
93
95
|
}
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
+
// Invoked by the other controllers (media-library)
|
98
|
+
insertAttachments(attachments, event) {
|
99
|
+
const editorAttachments = attachments.map((attachment) => {
|
100
|
+
const { blob, path, url } = attachment
|
101
|
+
const link = this.#markdownLinkFromUrl(blob.filename, path, blob.content_type)
|
102
|
+
|
103
|
+
this.#injectLink(link)
|
104
|
+
})
|
105
|
+
|
106
|
+
this.editor?.chain().focus().setAttachment(editorAttachments).run();
|
107
|
+
}
|
108
|
+
|
109
|
+
#uploadFiles(files) {
|
110
|
+
Array.from(files).forEach((file) => this.#uploadFile(file))
|
97
111
|
}
|
98
112
|
|
99
|
-
uploadFile(file) {
|
113
|
+
#uploadFile(file) {
|
100
114
|
const upload = new DirectUpload(file, this.attachUrlValue)
|
101
115
|
|
102
116
|
upload.create((error, blob) => {
|
103
117
|
if (error) {
|
104
118
|
console.log('Error', error)
|
105
119
|
} else {
|
106
|
-
const
|
107
|
-
|
108
|
-
const end = this.fieldElementTarget.selectionEnd
|
109
|
-
this.fieldElementTarget.setRangeText(text, start, end)
|
120
|
+
const link = this.#markdownLinkFromUrl(blob.filename, this.#pathFromBlob(blob), blob.content_type)
|
121
|
+
this.#injectLink(link)
|
110
122
|
}
|
111
123
|
})
|
112
124
|
}
|
113
125
|
|
114
|
-
|
115
|
-
const
|
116
|
-
const
|
117
|
-
|
126
|
+
#injectLink(link) {
|
127
|
+
const start = this.fieldElementTarget.selectionStart
|
128
|
+
const end = this.fieldElementTarget.selectionEnd
|
129
|
+
this.fieldElementTarget.setRangeText(link, start, end)
|
130
|
+
}
|
131
|
+
|
132
|
+
#pathFromBlob(blob) {
|
133
|
+
return `/rails/active_storage/blobs/redirect/${blob.signed_id}/${blob.filename}`
|
134
|
+
}
|
135
|
+
|
136
|
+
#markdownLinkFromUrl(filename, url, contentType) {
|
137
|
+
const prefix = (this.#isImage(contentType) ? '!' : '')
|
118
138
|
|
119
139
|
return `${prefix}[${filename}](${url})\n`
|
120
140
|
}
|
121
141
|
|
122
|
-
isImage(contentType) {
|
142
|
+
#isImage(contentType) {
|
123
143
|
return ['image/jpeg', 'image/gif', 'image/png'].includes(contentType)
|
124
144
|
}
|
125
145
|
}
|
@@ -13,6 +13,17 @@
|
|
13
13
|
local_assigns[:value] || nil
|
14
14
|
end
|
15
15
|
extra_preview_params = local_assigns[:extra_preview_params] || {}
|
16
|
+
|
17
|
+
# Used by Avo and other adapters to enable the gallery link.
|
18
|
+
gallery_enabled = local_assigns.dig(:gallery, :enabled) || false
|
19
|
+
gallery_open_path = local_assigns.dig(:gallery, :open_path) || nil
|
20
|
+
gallery_params = local_assigns.dig(:gallery, :params) || {}
|
21
|
+
if gallery_open_path.present?
|
22
|
+
gallery_full_path = gallery_open_path + "?" + gallery_params.map { |k,v| "#{k}=#{v}" }.join('&')
|
23
|
+
else
|
24
|
+
gallery_full_path = nil
|
25
|
+
end
|
26
|
+
gallery_turbo_frame = local_assigns.dig(:gallery, :turbo_frame) || nil
|
16
27
|
%>
|
17
28
|
<%= content_tag :div,
|
18
29
|
class: "ms:block ms:flex-col ms:w-full ms:border ms:border-neutral-300 ms:rounded ms:@container ms:focus-within:border-neutral-400",
|
@@ -22,10 +33,12 @@
|
|
22
33
|
beforeinput->list-continuation#handleBeforeInput
|
23
34
|
input->list-continuation#handleInput
|
24
35
|
",
|
36
|
+
unique_selector: ".#{@input_id}", # used to pinpoint the exact element in which to insert the attachment
|
25
37
|
marksmith_preview_url_value: marksmith.markdown_previews_path,
|
26
38
|
marksmith_active_tab_class: "bg-white",
|
27
39
|
marksmith_attach_url_value: main_app.rails_direct_uploads_url,
|
28
40
|
marksmith_extra_preview_params_value: extra_preview_params.as_json,
|
41
|
+
**local_assigns.fetch(:controller_data_attributes, {})
|
29
42
|
} do %>
|
30
43
|
<% 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") %>
|
31
44
|
<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">
|
@@ -69,11 +82,16 @@
|
|
69
82
|
style:
|
70
83
|
%>
|
71
84
|
<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">
|
72
|
-
<%= 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:
|
73
|
-
<%= image_tag asset_path("marksmith/svgs/markdown.svg"), class: "ms:inline ms:size-4" %> <%= t("marksmith.markdown_is_supported").humanize %>
|
85
|
+
<%= 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 %>
|
86
|
+
<%= image_tag asset_path("marksmith/svgs/markdown.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.markdown_is_supported").humanize %>
|
74
87
|
<% end %>
|
75
88
|
<%= 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 %>
|
76
|
-
<%= image_tag asset_path("marksmith/svgs/paperclip.svg"), class: "ms:inline ms:size-4" %> <%= t("marksmith.
|
89
|
+
<%= image_tag asset_path("marksmith/svgs/paperclip.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.upload_files").humanize %>
|
90
|
+
<% end %>
|
91
|
+
<% if gallery_enabled %>
|
92
|
+
<%= 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 %>
|
93
|
+
<%= image_tag asset_path("marksmith/svgs/gallery.svg"), class: "ms:inline ms:size-4 ms:mr-1" %> <%= t("marksmith.attach_from_gallery").humanize %>
|
94
|
+
<% end %>
|
77
95
|
<% end %>
|
78
96
|
</div>
|
79
97
|
<% end %>
|
@@ -30,7 +30,7 @@
|
|
30
30
|
|
31
31
|
en:
|
32
32
|
marksmith:
|
33
|
-
|
33
|
+
attach_from_gallery: Attach from gallery
|
34
34
|
bold: bold
|
35
35
|
code: code
|
36
36
|
header: header
|
@@ -43,4 +43,5 @@ en:
|
|
43
43
|
quote: quote
|
44
44
|
task_list: task_list
|
45
45
|
unordered_list: unordered list
|
46
|
+
upload_files: upload files
|
46
47
|
write: write
|
data/lib/marksmith/engine.rb
CHANGED
@@ -19,8 +19,33 @@ module Marksmith
|
|
19
19
|
|
20
20
|
initializer "marksmith.assets.precompile" do |app|
|
21
21
|
if Rails.application.config.respond_to?(:assets)
|
22
|
+
# The manifest will expose the asset files to the main app.
|
22
23
|
app.config.assets.precompile << "marksmith_manifest.js"
|
23
24
|
end
|
24
25
|
end
|
26
|
+
|
27
|
+
initializer "avo-markdown_field.init" do |app|
|
28
|
+
if defined?(Avo)
|
29
|
+
require "marksmith/fields/markdown_field"
|
30
|
+
|
31
|
+
app.routes.append do
|
32
|
+
mount Marksmith::Engine => "/marksmith"
|
33
|
+
end
|
34
|
+
|
35
|
+
ActiveSupport.on_load(:avo_boot) do
|
36
|
+
Avo.plugin_manager.register :marksmith_field
|
37
|
+
|
38
|
+
Avo.plugin_manager.register_field :markdown, Marksmith::Fields::MarkdownField
|
39
|
+
Avo.plugin_manager.register_field :marksmith, Marksmith::Fields::MarkdownField
|
40
|
+
|
41
|
+
Avo.asset_manager.add_stylesheet "marksmith"
|
42
|
+
Avo.asset_manager.add_javascript "marksmith_controller-no-stimulus.esm"
|
43
|
+
Avo.asset_manager.add_javascript "list_continuation_controller-no-stimulus.esm"
|
44
|
+
|
45
|
+
Avo.asset_manager.register_stimulus_controller "marksmith", "MarksmithController"
|
46
|
+
Avo.asset_manager.register_stimulus_controller "list-continuation", "ListContinuationController"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
25
50
|
end
|
26
51
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Marksmith
|
2
|
+
module Fields
|
3
|
+
class MarkdownField < Avo::Fields::BaseField
|
4
|
+
def initialize(id, **args, &block)
|
5
|
+
super(id, **args, &block)
|
6
|
+
|
7
|
+
hide_on :index
|
8
|
+
end
|
9
|
+
|
10
|
+
def view_component_namespace
|
11
|
+
"Marksmith::MarkdownField"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
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.0.
|
4
|
+
version: 0.0.16
|
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-01-
|
11
|
+
date: 2025-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- app/assets/images/marksmith/svgs/code.svg
|
54
54
|
- app/assets/images/marksmith/svgs/color-swatch copy.svg
|
55
55
|
- app/assets/images/marksmith/svgs/color-swatch.svg
|
56
|
+
- app/assets/images/marksmith/svgs/gallery.svg
|
56
57
|
- app/assets/images/marksmith/svgs/header.svg
|
57
58
|
- app/assets/images/marksmith/svgs/image.svg
|
58
59
|
- app/assets/images/marksmith/svgs/italic.svg
|
@@ -64,8 +65,16 @@ files:
|
|
64
65
|
- app/assets/images/marksmith/svgs/quote.svg
|
65
66
|
- app/assets/images/marksmith/svgs/task-list.svg
|
66
67
|
- app/assets/images/marksmith/svgs/unordered-list.svg
|
68
|
+
- app/assets/javascripts/list_continuation_controller-full.esm.js
|
69
|
+
- app/assets/javascripts/list_continuation_controller-no-stimulus.esm.js
|
70
|
+
- app/assets/javascripts/marksmith_controller-full.esm.js
|
71
|
+
- app/assets/javascripts/marksmith_controller-no-stimulus.esm.js
|
67
72
|
- app/assets/stylesheets/marksmith.css
|
68
73
|
- app/assets/stylesheets/marksmith/application.css
|
74
|
+
- app/components/marksmith/markdown_field/edit_component.html.erb
|
75
|
+
- app/components/marksmith/markdown_field/edit_component.rb
|
76
|
+
- app/components/marksmith/markdown_field/show_component.html.erb
|
77
|
+
- app/components/marksmith/markdown_field/show_component.rb
|
69
78
|
- app/controllers/marksmith/application_controller.rb
|
70
79
|
- app/controllers/marksmith/markdown_previews_controller.rb
|
71
80
|
- app/frontend/entrypoints/application.css
|
@@ -89,6 +98,7 @@ files:
|
|
89
98
|
- config/vite.json
|
90
99
|
- lib/marksmith.rb
|
91
100
|
- lib/marksmith/engine.rb
|
101
|
+
- lib/marksmith/fields/markdown_field.rb
|
92
102
|
- lib/marksmith/helper.rb
|
93
103
|
- lib/marksmith/version.rb
|
94
104
|
- lib/tasks/marksmith_tasks.rake
|
@@ -114,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
124
|
- !ruby/object:Gem::Version
|
115
125
|
version: '0'
|
116
126
|
requirements: []
|
117
|
-
rubygems_version: 3.
|
127
|
+
rubygems_version: 3.5.9
|
118
128
|
signing_key:
|
119
129
|
specification_version: 4
|
120
130
|
summary: Marksmith is a GitHub-style markdown editor for Ruby on Rails applications.
|