marksmith 0.0.15 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0da9e3c49eee802cb04a55505552636af16dd6821180a049bbdcdb51d0664ed6
4
- data.tar.gz: 1eddf93578ba14e3b0a79f5915f69efce8a24f28c6ce9cf4f5c94c8764f5c46b
3
+ metadata.gz: e75eb38c87cf55bb17635627ebf0c3fa043e8f936d13e36faa997c311a81767a
4
+ data.tar.gz: 6817d10490f87128ef997c34b1ffb666af6feb433bdde8a2f817b3f831995985
5
5
  SHA512:
6
- metadata.gz: a735566969ff5549736ae7588b20988f24caa424e60df3e41265d9aa9c6934175cebba2e39a51af159be790d91a99283873315beb14fcc080a7f08c7036bea3d
7
- data.tar.gz: afab9a21269662a84b2b63e9ea338db62e2e399b4dcf524801510168598413cf37ceba0e8bc0fd21fe9f463d14c4ad1a4c82d04c6f65ace47a778bdddb916e13
6
+ metadata.gz: 04f4b63bc45ad9ac1012aee2841e403678b6ef9ae7198e51c2bfeca355dbf04f97ec64220fd513a9bdc7455d46c79e33036f738c9449b0056d20baebc8bbe27d
7
+ data.tar.gz: 93db1009535a17a459f69cf34a93febe2505fa68aefc29adb8559bd626cd1d48c32c7578ba857b8b74ea26e3e74691b3c51ce64152d4092e5f81ad7a53c8841d
data/README.md CHANGED
@@ -4,7 +4,9 @@ Marksmith is a GitHub-style markdown editor for Rails apps.
4
4
 
5
5
  It supports Active Storage attachments and comes with a built-in mardown preview renderer.
6
6
 
7
- [![Marksmith demo](https://github.com/user-attachments/assets/09820413-7b2f-4d9d-a6a5-a9b1d5b90bea)](https://github.com/user-attachments/assets/f257db9d-6bfd-4fbc-ac10-dff1dfc99ff2)
7
+ ![Marksmith logo](./marksmith.png)
8
+
9
+ ![Marksmith demo](./marksmith.gif)
8
10
 
9
11
  ## Usage
10
12
 
@@ -107,7 +109,10 @@ bin/importmap pin @avo-hq/marksmith
107
109
 
108
110
  ## Active Storage
109
111
 
110
- The field supports Actve Storage uploads using drag and drop and pasting files into the field.
112
+ The editor supports [ActiveStorage](https://guides.rubyonrails.org/active_storage_overview.html) uploads using drag and drop and pasting files into the field.
113
+
114
+ Whe used in Avo it supports injecting assets using the [Media Library feature](http://docs.avohq.io/3.0/media-library.html).
115
+
111
116
 
112
117
  ## List Continuation
113
118
 
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-images"><path d="M18 22H4a2 2 0 0 1-2-2V6"/><path d="m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18"/><circle cx="12" cy="8" r="2"/><rect width="16" height="16" x="6" y="2" rx="2"/></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="800px" height="800px" viewBox="0 0 24 24" role="img"><script xmlns="" src="chrome-extension://hoklmmgfnpapgjgcpechhaamimifchmp/frame_ant/frame_ant.js"/><title>Markdown icon</title><path d="M22.269 19.385H1.731a1.73 1.73 0 0 1-1.73-1.73V6.345a1.73 1.73 0 0 1 1.73-1.73h20.538a1.73 1.73 0 0 1 1.73 1.73v11.308a1.73 1.73 0 0 1-1.73 1.731zm-16.5-3.462v-4.5l2.308 2.885 2.307-2.885v4.5h2.308V8.078h-2.308l-2.307 2.885-2.308-2.885H3.461v7.847zM21.231 12h-2.308V8.077h-2.307V12h-2.308l3.461 4.039z"/></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" role="img"><script xmlns="" src="chrome-extension://hoklmmgfnpapgjgcpechhaamimifchmp/frame_ant/frame_ant.js"/><title>Markdown icon</title><path d="M22.269 19.385H1.731a1.73 1.73 0 0 1-1.73-1.73V6.345a1.73 1.73 0 0 1 1.73-1.73h20.538a1.73 1.73 0 0 1 1.73 1.73v11.308a1.73 1.73 0 0 1-1.73 1.731zm-16.5-3.462v-4.5l2.308 2.885 2.307-2.885v4.5h2.308V8.078h-2.308l-2.307 2.885-2.308-2.885H3.461v7.847zM21.231 12h-2.308V8.077h-2.307V12h-2.308l3.461 4.039z"/></svg>
@@ -1,3 +1,3 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
2
2
  <path stroke-linecap="round" stroke-linejoin="round" d="m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" />
3
3
  </svg>
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Marksmith 0.0.15
2
+ Marksmith 0.1.0
3
3
  */
4
4
  var ListContinuationController = (function () {
5
5
  'use strict';
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Marksmith 0.0.15
2
+ Marksmith 0.1.0
3
3
  */
4
4
  var ListContinuationController = (function (stimulus) {
5
5
  'use strict';
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Marksmith 0.0.15
2
+ Marksmith 0.1.0
3
3
  */
4
4
  var MarksmithController = (function () {
5
5
  'use strict';
@@ -2825,6 +2825,8 @@ var MarksmithController = (function () {
2825
2825
  previewUrl: String,
2826
2826
  extraPreviewParams: { type: Object, default: {} },
2827
2827
  fieldId: String,
2828
+ galleryEnabled: { type: Boolean, default: false },
2829
+ galleryOpenPath: String,
2828
2830
  }
2829
2831
 
2830
2832
  static targets = ['fieldContainer', 'fieldElement', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
@@ -2877,14 +2879,14 @@ var MarksmithController = (function () {
2877
2879
 
2878
2880
  dropUpload(event) {
2879
2881
  event.preventDefault();
2880
- this.uploadFiles(event.dataTransfer.files);
2882
+ this.#uploadFiles(event.dataTransfer.files);
2881
2883
  }
2882
2884
 
2883
2885
  pasteUpload(event) {
2884
2886
  if (!event.clipboardData.files.length) return
2885
2887
 
2886
2888
  event.preventDefault();
2887
- this.uploadFiles(event.clipboardData.files);
2889
+ this.#uploadFiles(event.clipboardData.files);
2888
2890
  }
2889
2891
 
2890
2892
  buttonUpload(event) {
@@ -2896,40 +2898,58 @@ var MarksmithController = (function () {
2896
2898
  fileInput.accept = 'image/*,.pdf,.doc,.docx,.txt';
2897
2899
 
2898
2900
  fileInput.addEventListener('change', (e) => {
2899
- this.uploadFiles(e.target.files);
2901
+ this.#uploadFiles(e.target.files);
2900
2902
  });
2901
2903
 
2902
2904
  fileInput.click();
2903
2905
  }
2904
2906
 
2905
- uploadFiles(files) {
2906
- Array.from(files).forEach((file) => this.uploadFile(file));
2907
+ // Invoked by the other controllers (media-library)
2908
+ insertAttachments(attachments, event) {
2909
+ const editorAttachments = attachments.map((attachment) => {
2910
+ const { blob, path, url } = attachment;
2911
+ const link = this.#markdownLinkFromUrl(blob.filename, path, blob.content_type);
2912
+
2913
+ this.#injectLink(link);
2914
+ });
2915
+
2916
+ this.editor?.chain().focus().setAttachment(editorAttachments).run();
2917
+ }
2918
+
2919
+ #uploadFiles(files) {
2920
+ Array.from(files).forEach((file) => this.#uploadFile(file));
2907
2921
  }
2908
2922
 
2909
- uploadFile(file) {
2923
+ #uploadFile(file) {
2910
2924
  const upload = new DirectUpload(file, this.attachUrlValue);
2911
2925
 
2912
2926
  upload.create((error, blob) => {
2913
2927
  if (error) {
2914
2928
  console.log('Error', error);
2915
2929
  } else {
2916
- const text = this.markdownLink(blob);
2917
- const start = this.fieldElementTarget.selectionStart;
2918
- const end = this.fieldElementTarget.selectionEnd;
2919
- this.fieldElementTarget.setRangeText(text, start, end);
2930
+ const link = this.#markdownLinkFromUrl(blob.filename, this.#pathFromBlob(blob), blob.content_type);
2931
+ this.#injectLink(link);
2920
2932
  }
2921
2933
  });
2922
2934
  }
2923
2935
 
2924
- markdownLink(blob) {
2925
- const { filename } = blob;
2926
- const url = `/rails/active_storage/blobs/${blob.signed_id}/${filename}`;
2927
- const prefix = (this.isImage(blob.content_type) ? '!' : '');
2936
+ #injectLink(link) {
2937
+ const start = this.fieldElementTarget.selectionStart;
2938
+ const end = this.fieldElementTarget.selectionEnd;
2939
+ this.fieldElementTarget.setRangeText(link, start, end);
2940
+ }
2941
+
2942
+ #pathFromBlob(blob) {
2943
+ return `/rails/active_storage/blobs/redirect/${blob.signed_id}/${blob.filename}`
2944
+ }
2945
+
2946
+ #markdownLinkFromUrl(filename, url, contentType) {
2947
+ const prefix = (this.#isImage(contentType) ? '!' : '');
2928
2948
 
2929
2949
  return `${prefix}[${filename}](${url})\n`
2930
2950
  }
2931
2951
 
2932
- isImage(contentType) {
2952
+ #isImage(contentType) {
2933
2953
  return ['image/jpeg', 'image/gif', 'image/png'].includes(contentType)
2934
2954
  }
2935
2955
  }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Marksmith 0.0.15
2
+ Marksmith 0.1.0
3
3
  */
4
4
  var MarksmithController = (function (stimulus) {
5
5
  'use strict';
@@ -2335,6 +2335,8 @@ var MarksmithController = (function (stimulus) {
2335
2335
  previewUrl: String,
2336
2336
  extraPreviewParams: { type: Object, default: {} },
2337
2337
  fieldId: String,
2338
+ galleryEnabled: { type: Boolean, default: false },
2339
+ galleryOpenPath: String,
2338
2340
  }
2339
2341
 
2340
2342
  static targets = ['fieldContainer', 'fieldElement', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
@@ -2387,14 +2389,14 @@ var MarksmithController = (function (stimulus) {
2387
2389
 
2388
2390
  dropUpload(event) {
2389
2391
  event.preventDefault();
2390
- this.uploadFiles(event.dataTransfer.files);
2392
+ this.#uploadFiles(event.dataTransfer.files);
2391
2393
  }
2392
2394
 
2393
2395
  pasteUpload(event) {
2394
2396
  if (!event.clipboardData.files.length) return
2395
2397
 
2396
2398
  event.preventDefault();
2397
- this.uploadFiles(event.clipboardData.files);
2399
+ this.#uploadFiles(event.clipboardData.files);
2398
2400
  }
2399
2401
 
2400
2402
  buttonUpload(event) {
@@ -2406,40 +2408,58 @@ var MarksmithController = (function (stimulus) {
2406
2408
  fileInput.accept = 'image/*,.pdf,.doc,.docx,.txt';
2407
2409
 
2408
2410
  fileInput.addEventListener('change', (e) => {
2409
- this.uploadFiles(e.target.files);
2411
+ this.#uploadFiles(e.target.files);
2410
2412
  });
2411
2413
 
2412
2414
  fileInput.click();
2413
2415
  }
2414
2416
 
2415
- uploadFiles(files) {
2416
- Array.from(files).forEach((file) => this.uploadFile(file));
2417
+ // Invoked by the other controllers (media-library)
2418
+ insertAttachments(attachments, event) {
2419
+ const editorAttachments = attachments.map((attachment) => {
2420
+ const { blob, path, url } = attachment;
2421
+ const link = this.#markdownLinkFromUrl(blob.filename, path, blob.content_type);
2422
+
2423
+ this.#injectLink(link);
2424
+ });
2425
+
2426
+ this.editor?.chain().focus().setAttachment(editorAttachments).run();
2427
+ }
2428
+
2429
+ #uploadFiles(files) {
2430
+ Array.from(files).forEach((file) => this.#uploadFile(file));
2417
2431
  }
2418
2432
 
2419
- uploadFile(file) {
2433
+ #uploadFile(file) {
2420
2434
  const upload = new DirectUpload(file, this.attachUrlValue);
2421
2435
 
2422
2436
  upload.create((error, blob) => {
2423
2437
  if (error) {
2424
2438
  console.log('Error', error);
2425
2439
  } else {
2426
- const text = this.markdownLink(blob);
2427
- const start = this.fieldElementTarget.selectionStart;
2428
- const end = this.fieldElementTarget.selectionEnd;
2429
- this.fieldElementTarget.setRangeText(text, start, end);
2440
+ const link = this.#markdownLinkFromUrl(blob.filename, this.#pathFromBlob(blob), blob.content_type);
2441
+ this.#injectLink(link);
2430
2442
  }
2431
2443
  });
2432
2444
  }
2433
2445
 
2434
- markdownLink(blob) {
2435
- const { filename } = blob;
2436
- const url = `/rails/active_storage/blobs/${blob.signed_id}/${filename}`;
2437
- const prefix = (this.isImage(blob.content_type) ? '!' : '');
2446
+ #injectLink(link) {
2447
+ const start = this.fieldElementTarget.selectionStart;
2448
+ const end = this.fieldElementTarget.selectionEnd;
2449
+ this.fieldElementTarget.setRangeText(link, start, end);
2450
+ }
2451
+
2452
+ #pathFromBlob(blob) {
2453
+ return `/rails/active_storage/blobs/redirect/${blob.signed_id}/${blob.filename}`
2454
+ }
2455
+
2456
+ #markdownLinkFromUrl(filename, url, contentType) {
2457
+ const prefix = (this.#isImage(contentType) ? '!' : '');
2438
2458
 
2439
2459
  return `${prefix}[${filename}](${url})\n`
2440
2460
  }
2441
2461
 
2442
- isImage(contentType) {
2462
+ #isImage(contentType) {
2443
2463
  return ['image/jpeg', 'image/gif', 'image/png'].includes(contentType)
2444
2464
  }
2445
2465
  }
@@ -1,5 +1,5 @@
1
- /*! tailwindcss v4.0.0-beta.10 | MIT License | https://tailwindcss.com */
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
  }
@@ -854,6 +854,9 @@
854
854
  margin-inline-end: calc(calc(var(--ms-spacing) * 2) * calc(1 - var(--tw-space-x-reverse)));
855
855
  }
856
856
  }
857
+ .ms\:overflow-auto {
858
+ overflow: auto;
859
+ }
857
860
  .ms\:rounded {
858
861
  border-radius: 0.25rem;
859
862
  }
@@ -900,15 +903,9 @@
900
903
  .ms\:px-2 {
901
904
  padding-inline: calc(var(--ms-spacing) * 2);
902
905
  }
903
- .ms\:px-3 {
904
- padding-inline: calc(var(--ms-spacing) * 3);
905
- }
906
906
  .ms\:py-1 {
907
907
  padding-block: calc(var(--ms-spacing) * 1);
908
908
  }
909
- .ms\:py-2 {
910
- padding-block: calc(var(--ms-spacing) * 2);
911
- }
912
909
  .ms\:py-px {
913
910
  padding-block: 1px;
914
911
  }
@@ -1027,6 +1024,9 @@
1027
1024
  flex-direction: row;
1028
1025
  }
1029
1026
  }
1027
+ .marksmith, .marksmith * {
1028
+ box-sizing: border-box;
1029
+ }
1030
1030
  .ms\:button-spinner {
1031
1031
  width: 24px;
1032
1032
  height: 24px;
@@ -1,5 +1,19 @@
1
1
  <%= field_wrapper **field_wrapper_args, full_width: true do %>
2
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
+ },
3
17
  extra_preview_params: {
4
18
  resource_class: @resource.class.name,
5
19
  field_id: field.id,
@@ -1,4 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Marksmith::MarkdownField::EditComponent < Avo::Fields::EditComponent
4
+ def unique_id
5
+ [@field.type, @resource&.singular_route_key, @field.id].compact.join("_")
6
+ end
4
7
  end
@@ -12,6 +12,11 @@
12
12
  @source "./../../helpers/";
13
13
  @source "./../../../lib/";
14
14
 
15
+ .marksmith,
16
+ .marksmith * {
17
+ box-sizing: border-box;
18
+ }
19
+
15
20
  .ms\:button-spinner {
16
21
  width: 24px;
17
22
  height: 24px;
@@ -1,7 +1,9 @@
1
1
  import { application } from "./application"
2
2
 
3
3
  import MarksmithController from "./marksmith_controller"
4
+ import ListContinuationController from "./list_continuation_controller"
4
5
  // import MarksmithController from "./../../../../../app/assets/builds/marksmith.esm.js"
5
6
  // console.log(MarksmithController)
6
7
 
7
8
  application.register("marksmith", MarksmithController)
9
+ application.register("list-continuation", ListContinuationController)
@@ -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.uploadFiles(event.dataTransfer.files)
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.uploadFiles(event.clipboardData.files)
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.uploadFiles(e.target.files)
91
+ this.#uploadFiles(e.target.files)
90
92
  })
91
93
 
92
94
  fileInput.click()
93
95
  }
94
96
 
95
- uploadFiles(files) {
96
- Array.from(files).forEach((file) => this.uploadFile(file))
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 text = this.markdownLink(blob)
107
- const start = this.fieldElementTarget.selectionStart
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
- markdownLink(blob) {
115
- const { filename } = blob
116
- const url = `/rails/active_storage/blobs/${blob.signed_id}/${filename}`
117
- const prefix = (this.isImage(blob.content_type) ? '!' : '')
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
  }
@@ -1,6 +1,4 @@
1
1
  <%= turbo_stream.update params[:element_id] do %>
2
- <div class="ms:px-3 ms:py-2">
3
- <%= render partial: "marksmith/shared/rendered_body", locals: { body: @body } %>
4
- </div>
2
+ <%= render partial: "marksmith/shared/rendered_body", locals: { body: @body } %>
5
3
  <% end %>
6
4
 
@@ -13,19 +13,32 @@
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
- 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",
29
+ 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",
19
30
  data: {
20
31
  controller: "marksmith list-continuation",
21
32
  action: "
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">
@@ -52,11 +65,11 @@
52
65
  </markdown-toolbar>
53
66
  </div>
54
67
  <% toolbar_button_classes = "ms:cursor-pointer ms:hover:bg-neutral-100 ms:px-1 ms:py-px ms:rounded ms:text-sm" %>
55
- <div class="ms:border-t ms:w-full ms:border-neutral-300 ms:flex">
56
- <%= content_tag :div, class: "ms:flex ms:flex-col ms:size-full", data: { marksmith_target: "fieldContainer" } do %>
68
+ <div class="ms:border-t ms:w-full ms:border-neutral-300 ms:flex ms:flex-1">
69
+ <%= content_tag :div, class: "ms:flex ms:flex-1 ms:flex-col ms:size-full", data: { marksmith_target: "fieldContainer" } do %>
57
70
  <%= text_area_tag field_name, value,
58
71
  id: name,
59
- class: class_names("ms:flex ms:flex-1 ms:rounded ms:border-none ms:p-2 ms:resize-y ms:focus:outline-none ms:font-mono ms:focus:ring-0 ms:leading-normal", classes),
72
+ class: class_names("ms:flex ms:flex-1 ms:rounded ms:border-none ms:resize-y ms:focus:outline-none ms:font-mono ms:focus:ring-0 ms:leading-normal ms:p-2", classes),
60
73
  rows: rows,
61
74
  data: {
62
75
  action: "drop->marksmith#dropUpload paste->marksmith#pasteUpload",
@@ -68,17 +81,22 @@
68
81
  autofocus:,
69
82
  style:
70
83
  %>
71
- <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:gap-x-2 ms:text-neutral-800 ms:no-underline", toolbar_button_classes) do %>
73
- <%= image_tag asset_path("marksmith/svgs/markdown.svg"), class: "ms:inline ms:size-4" %> <%= t("marksmith.markdown_is_supported").humanize %>
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 ms:p-2">
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.attach_files").humanize %>
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 %>
80
98
  <%= content_tag :div,
81
- class: "ms:hidden ms:markdown-preview ms:size-full ms:flex-1 ms:flex ms:size-full",
99
+ class: "ms:hidden ms:markdown-preview ms:size-full ms:flex-1 ms:flex ms:size-full ms:p-2 ms:overflow-auto",
82
100
  id: "markdown-preview-#{name}",
83
101
  data: {
84
102
  marksmith_target: "previewElement",
@@ -1,3 +1,3 @@
1
- <%= content_tag :div, class: "ms:prose ms:prose-neutral ms:max-w-none" do %>
1
+ <%= content_tag :div, class: "ms:block ms:w-full ms:prose ms:max-w-none ms:prose-neutral" 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 %>
@@ -30,7 +30,7 @@
30
30
 
31
31
  en:
32
32
  marksmith:
33
- attach_files: attach files
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
@@ -1,3 +1,3 @@
1
1
  module Marksmith
2
- VERSION = "0.0.15"
2
+ VERSION = "0.1.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.0.15
4
+ version: 0.1.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-01-25 00:00:00.000000000 Z
11
+ date: 2025-02-03 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
@@ -123,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
124
  - !ruby/object:Gem::Version
124
125
  version: '0'
125
126
  requirements: []
126
- rubygems_version: 3.4.10
127
+ rubygems_version: 3.5.9
127
128
  signing_key:
128
129
  specification_version: 4
129
130
  summary: Marksmith is a GitHub-style markdown editor for Ruby on Rails applications.