pages_core 3.12.4 → 3.12.5

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/builds/pages_core/admin-dist.js +8 -43
  4. data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
  5. data/app/assets/builds/pages_core/admin.css +264 -133
  6. data/app/assets/stylesheets/pages_core/admin/components/attachments.css +3 -4
  7. data/app/assets/stylesheets/pages_core/admin/components/forms.css +17 -16
  8. data/app/assets/stylesheets/pages_core/admin/components/image_editor.css +8 -4
  9. data/app/assets/stylesheets/pages_core/admin/components/image_grid.css +1 -1
  10. data/app/assets/stylesheets/pages_core/admin/components/list_table.css +11 -3
  11. data/app/assets/stylesheets/pages_core/admin/components/modal.css +9 -5
  12. data/app/assets/stylesheets/pages_core/admin/components/page_tree.css +5 -1
  13. data/app/assets/stylesheets/pages_core/admin/components/toast.css +2 -2
  14. data/app/assets/stylesheets/pages_core/admin/controllers/pages.css +4 -2
  15. data/app/assets/stylesheets/pages_core/admin/vars.css +2 -1
  16. data/app/controllers/admin/calendars_controller.rb +2 -2
  17. data/app/controllers/admin/categories_controller.rb +3 -3
  18. data/app/controllers/admin/news_controller.rb +6 -6
  19. data/app/controllers/admin/pages_controller.rb +12 -11
  20. data/app/controllers/admin/users_controller.rb +1 -1
  21. data/app/controllers/concerns/pages_core/preview_pages_controller.rb +15 -17
  22. data/app/controllers/pages_core/admin_controller.rb +2 -2
  23. data/app/controllers/pages_core/base_controller.rb +1 -8
  24. data/app/controllers/pages_core/frontend/pages_controller.rb +13 -5
  25. data/app/controllers/pages_core/frontend_controller.rb +12 -7
  26. data/app/helpers/admin/menu_helper.rb +2 -0
  27. data/app/helpers/admin/pages_helper.rb +1 -4
  28. data/app/helpers/pages_core/admin/admin_helper.rb +0 -1
  29. data/app/helpers/pages_core/admin/content_tabs_helper.rb +9 -2
  30. data/app/helpers/pages_core/application_helper.rb +2 -3
  31. data/app/helpers/pages_core/frontend_helper.rb +1 -1
  32. data/app/helpers/pages_core/head_tags_helper.rb +15 -46
  33. data/app/helpers/pages_core/images_helper.rb +76 -21
  34. data/app/helpers/pages_core/locales_helper.rb +9 -0
  35. data/app/helpers/pages_core/open_graph_tags_helper.rb +3 -5
  36. data/app/helpers/pages_core/page_path_helper.rb +1 -1
  37. data/app/javascript/components/Attachments/Attachment.tsx +55 -52
  38. data/app/javascript/components/Attachments/AttachmentEditor.tsx +45 -50
  39. data/app/javascript/components/Attachments/Placeholder.tsx +1 -2
  40. data/app/javascript/components/Attachments.jsx +69 -57
  41. data/app/javascript/components/DateRangeSelect.jsx +94 -54
  42. data/app/javascript/components/EditableImage.tsx +20 -16
  43. data/app/javascript/components/FileUploadButton.tsx +12 -12
  44. data/app/javascript/components/ImageCropper/FocalPoint.tsx +22 -20
  45. data/app/javascript/components/ImageCropper/Image.tsx +20 -16
  46. data/app/javascript/components/ImageCropper/Toolbar.tsx +35 -27
  47. data/app/javascript/components/ImageCropper/useCrop.ts +105 -91
  48. data/app/javascript/components/ImageCropper.tsx +34 -25
  49. data/app/javascript/components/ImageEditor/Form.tsx +32 -43
  50. data/app/javascript/components/ImageEditor.tsx +29 -21
  51. data/app/javascript/components/ImageGrid/DragElement.tsx +6 -4
  52. data/app/javascript/components/ImageGrid/GridImage.tsx +56 -52
  53. data/app/javascript/components/ImageGrid/Placeholder.tsx +1 -1
  54. data/app/javascript/components/ImageGrid.jsx +132 -101
  55. data/app/javascript/components/ImageUploader.tsx +59 -55
  56. data/app/javascript/components/Modal.tsx +2 -4
  57. data/app/javascript/components/PageDates.jsx +25 -20
  58. data/app/javascript/components/PageFiles.jsx +7 -5
  59. data/app/javascript/components/PageImages.tsx +9 -7
  60. data/app/javascript/components/PageTree/Draggable.tsx +46 -40
  61. data/app/javascript/components/PageTree/Node.tsx +111 -95
  62. data/app/javascript/components/PageTree/types.ts +9 -9
  63. data/app/javascript/components/PageTree.tsx +44 -29
  64. data/app/javascript/components/RichTextArea.jsx +51 -37
  65. data/app/javascript/components/RichTextToolbarButton.tsx +8 -5
  66. data/app/javascript/components/TagEditor/AddTagForm.tsx +11 -10
  67. data/app/javascript/components/TagEditor/Tag.tsx +10 -8
  68. data/app/javascript/components/TagEditor.tsx +15 -10
  69. data/app/javascript/components/Toast.tsx +3 -7
  70. data/app/javascript/components/drag/draggedOrder.ts +16 -15
  71. data/app/javascript/components/drag/types.ts +12 -12
  72. data/app/javascript/components/drag/useDragCollection.ts +36 -42
  73. data/app/javascript/components/drag/useDragUploader.ts +3 -2
  74. data/app/javascript/components/drag.ts +5 -4
  75. data/app/javascript/controllers/LoginController.ts +0 -1
  76. data/app/javascript/controllers/MainController.ts +6 -2
  77. data/app/javascript/controllers/PageOptionsController.js +7 -2
  78. data/app/javascript/features/RichText.tsx +9 -7
  79. data/app/javascript/index.ts +5 -3
  80. data/app/javascript/lib/Tree.ts +27 -24
  81. data/app/javascript/lib/copyToClipboard.ts +5 -4
  82. data/app/javascript/lib/readyHandler.ts +4 -4
  83. data/app/javascript/lib/request.ts +7 -3
  84. data/app/javascript/stores/useModalStore.ts +3 -3
  85. data/app/javascript/stores/useToastStore.ts +14 -12
  86. data/app/javascript/types.ts +22 -22
  87. data/app/models/concerns/pages_core/page_model/templateable.rb +1 -1
  88. data/app/views/admin/calendars/show.html.erb +1 -1
  89. data/app/views/admin/news/index.html.erb +1 -1
  90. data/app/views/admin/pages/_edit_files.html.erb +1 -1
  91. data/app/views/admin/pages/_edit_images.html.erb +1 -1
  92. data/app/views/admin/pages/_list_item.html.erb +1 -1
  93. data/app/views/admin/pages/_search_bar.html.erb +1 -1
  94. data/app/views/admin/pages/deleted.html.erb +2 -2
  95. data/app/views/admin/pages/edit.html.erb +3 -3
  96. data/app/views/admin/pages/index.html.erb +4 -4
  97. data/app/views/admin/pages/new.html.erb +1 -1
  98. data/app/views/admin/pages/search.html.erb +3 -3
  99. data/app/views/feeds/pages.rss.builder +2 -2
  100. data/app/views/layouts/admin/_page_header.html.erb +4 -4
  101. data/app/views/layouts/admin.html.erb +1 -2
  102. data/config/locales/en.yml +1 -0
  103. data/lib/pages_core/pages_plugin.rb +5 -3
  104. data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +15 -13
  105. data/lib/tasks/pages/reports.rake +26 -0
  106. metadata +32 -4
  107. data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +0 -40
  108. data/app/views/pages_core/_google_analytics.html.erb +0 -8
@@ -3,7 +3,7 @@
3
3
  module PagesCore
4
4
  module FrontendHelper
5
5
  def root_pages
6
- @root_pages ||= Page.roots.localized(@locale).published
6
+ @root_pages ||= Page.roots.localized(content_locale).published
7
7
  end
8
8
 
9
9
  def root_page
@@ -10,13 +10,10 @@ module PagesCore
10
10
  if args.any?
11
11
  @document_title = args.first
12
12
  else
13
- safe_join(
14
- [@document_title, PagesCore.config(:site_name)].compact.uniq,
15
- " - "
16
- )
13
+ safe_join([@document_title, PagesCore.config(:site_name)].compact.uniq,
14
+ " - ")
17
15
  end
18
16
  end
19
- alias page_title document_title
20
17
 
21
18
  # Returns true if document title has been set.
22
19
  def document_title?
@@ -30,28 +27,19 @@ module PagesCore
30
27
  # feed_tags include_hidden: true
31
28
  #
32
29
  def feed_tags(options = {})
33
- feeds = Page.enabled_feeds(@locale, options)
30
+ feeds = Page.enabled_feeds(content_locale, options)
34
31
  return unless feeds.any?
35
32
 
36
33
  feed_tags = [
37
34
  rss_link_tag(PagesCore.config(:site_name),
38
- pages_url(@locale, format: :rss))
35
+ pages_url(content_locale, format: :rss))
39
36
  ] + feeds.map do |page|
40
37
  rss_link_tag("#{PagesCore.config(:site_name)}: #{page.name}",
41
- page_url(@locale, page, format: :rss))
38
+ page_url(content_locale, page, format: :rss))
42
39
  end
43
40
  safe_join(feed_tags, "\n")
44
41
  end
45
42
 
46
- # Outputs Google Analytics tracking code.
47
- #
48
- # google_analytics_tags "UA-12345678-1"
49
- #
50
- def google_analytics_tags(account_id)
51
- render(partial: "pages_core/google_analytics",
52
- locals: { account_id: account_id })
53
- end
54
-
55
43
  # Outputs a HTML5 doctype and head tags, with document title
56
44
  # and relevant meta tags. Takes a block which will be placed
57
45
  # inside <head>.
@@ -66,14 +54,7 @@ module PagesCore
66
54
  # The block output must be captured first
67
55
  block_output = block_given? ? capture(&block) : nil
68
56
 
69
- safe_join(
70
- [
71
- "<!doctype html>\n<html lang=\"#{I18n.locale}\">".html_safe,
72
- tag.head do
73
- safe_join(head_tag_contents(block_output), "\n")
74
- end
75
- ]
76
- )
57
+ tag.head { safe_join(head_tag_contents(block_output), "\n") }
77
58
  end
78
59
 
79
60
  # Generates a link to an RSS feed.
@@ -87,30 +68,18 @@ module PagesCore
87
68
  href: href)
88
69
  end
89
70
 
90
- # Outputs Typekit tags.
91
- #
92
- # typekit_tags "aadgrag"
93
- #
94
- def typekit_tags(kit_id)
95
- safe_join([
96
- javascript_include_tag("http://use.typekit.com/#{kit_id}.js"),
97
- javascript_tag("try{Typekit.load();}catch(e){}")
98
- ], "\n")
99
- end
100
-
101
71
  private
102
72
 
103
73
  def head_tag_contents(block_output)
104
- [
105
- tag.meta(charset: "utf-8"),
106
- tag.meta("http-equiv" => "X-UA-Compatible", "content" => "IE=edge"),
107
- tag.title(document_title),
108
- meta_description_tag, meta_keywords_tag,
109
- (tag.link(rel: "image_src", href: meta_image) if meta_image?),
110
- open_graph_tags,
111
- csrf_meta_tags,
112
- block_output
113
- ]
74
+ [tag.meta(charset: "utf-8"),
75
+ tag.meta("http-equiv" => "X-UA-Compatible", "content" => "IE=edge"),
76
+ tag.title(document_title),
77
+ meta_description_tag,
78
+ meta_keywords_tag,
79
+ (tag.link(rel: "image_src", href: meta_image) if meta_image?),
80
+ open_graph_tags,
81
+ csrf_meta_tags,
82
+ block_output]
114
83
  end
115
84
 
116
85
  def meta_description_tag
@@ -5,10 +5,8 @@ module PagesCore
5
5
  include DynamicImage::Helper
6
6
 
7
7
  def dynamic_image_tag(record_or_array, options = {})
8
- super(
9
- record_or_array,
10
- extract_alt_text(record_or_array).merge(options)
11
- )
8
+ super(record_or_array,
9
+ extract_alt_text(record_or_array).merge(options))
12
10
  end
13
11
 
14
12
  def image_caption(image, caption: nil)
@@ -32,25 +30,51 @@ module PagesCore
32
30
  def image_figure(image, opts = {})
33
31
  class_name = ["image", image_class_name(image), opts[:class_name]].compact
34
32
  image_tag = image_figure_image_tag(image,
35
- size: opts[:size], ratio:
36
- opts[:ratio])
33
+ size: opts[:size],
34
+ ratio: opts[:ratio])
37
35
  content = opts[:link] ? image_link_to(image_tag, opts[:link]) : image_tag
38
36
  tag.figure(content + image_caption(image, caption: opts[:caption]),
39
37
  class: class_name)
40
38
  end
41
39
 
40
+ # Renders an image figure tag with caption.
41
+ #
42
+ # ==== Options
43
+ # * <tt>:caption</tt>: Override caption with a string, or set to false to
44
+ # disable captions.
45
+ # * <tt>:class_name</tt>: Class name to add to figure tag.
46
+ # * <tt>:link</tt>: Link target for image.
47
+ # * <tt>:ratio</tt>: Ratio to constrain image by.
48
+ # * <tt>:sizes</tt>: Sizes attribute for image tag, default: "100vw".
49
+ def picture(image, opts = {})
50
+ class_name = ["image", image_class_name(image), opts[:class_name]].compact
51
+ pict = picture_tag(image, ratio: opts[:ratio], sizes: opts[:sizes])
52
+ content = opts[:link] ? image_link_to(pict, opts[:link]) : pict
53
+ tag.figure(content + image_caption(image, caption: opts[:caption]),
54
+ class: class_name)
55
+ end
56
+
57
+ def picture_tag(image, ratio: nil, sizes: "100vw")
58
+ tag.picture do
59
+ safe_join(
60
+ [webp_source(image, ratio: ratio, sizes: sizes || "100vw"),
61
+ dynamic_image_tag(image,
62
+ size: image_size(1050, ratio),
63
+ crop: (ratio ? true : false),
64
+ sizes: sizes,
65
+ srcset: srcset(image, ratio: ratio))]
66
+ )
67
+ end
68
+ end
69
+
42
70
  def original_dynamic_image_tag(record_or_array, options = {})
43
- super(
44
- record_or_array,
45
- extract_alt_text(record_or_array).merge(options)
46
- )
71
+ super(record_or_array,
72
+ extract_alt_text(record_or_array).merge(options))
47
73
  end
48
74
 
49
75
  def uncropped_dynamic_image_tag(record_or_array, options = {})
50
- super(
51
- record_or_array,
52
- extract_alt_text(record_or_array).merge(options)
53
- )
76
+ super(record_or_array,
77
+ extract_alt_text(record_or_array).merge(options))
54
78
  end
55
79
 
56
80
  private
@@ -72,13 +96,10 @@ module PagesCore
72
96
  end
73
97
 
74
98
  def image_class_name(image)
75
- if image.size.x == image.size.y
76
- "square"
77
- elsif image.size.x > image.size.y
78
- "landscape"
79
- else
80
- "portrait"
81
- end
99
+ return "square" if image.size.x == image.size.y
100
+ return "landscape" if image.size.x > image.size.y
101
+
102
+ "portrait"
82
103
  end
83
104
 
84
105
  def image_figure_image_tag(image, size: nil, ratio: nil)
@@ -91,5 +112,39 @@ module PagesCore
91
112
  def image_link_to(content, href)
92
113
  tag.a(content, href: href)
93
114
  end
115
+
116
+ def image_size(width, ratio)
117
+ return "#{width}x" unless ratio
118
+
119
+ "#{width}x#{(width / ratio).round}"
120
+ end
121
+
122
+ def image_widths(image)
123
+ [233, 350, 700, 1050, 1400, 2100, 2800].select do |w|
124
+ image.size.x >= w
125
+ end
126
+ end
127
+
128
+ def srcset(image, ratio: nil, format: nil)
129
+ image_widths(image).map do |width|
130
+ options = { size: image_size(width, ratio),
131
+ crop: (ratio ? true : false) }
132
+ options[:format] = format if format
133
+
134
+ "#{dynamic_image_path(image, options)} #{width}w"
135
+ end.join(", ")
136
+ end
137
+
138
+ def webp_source(image, ratio: nil, sizes: "100vw")
139
+ return unless webp_compatible?(image)
140
+
141
+ tag.source(type: "image/webp",
142
+ srcset: srcset(image, ratio: ratio, format: :webp),
143
+ sizes: sizes)
144
+ end
145
+
146
+ def webp_compatible?(image)
147
+ image.content_type != "image/gif"
148
+ end
94
149
  end
95
150
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PagesCore
4
+ module LocalesHelper
5
+ def content_locale
6
+ params[:locale] || I18n.default_locale.to_s
7
+ end
8
+ end
9
+ end
@@ -11,7 +11,7 @@ module PagesCore
11
11
  properties = default_open_graph_properties.merge(open_graph_properties)
12
12
  safe_join(
13
13
  properties
14
- .delete_if { |_, content| content.nil? }
14
+ .compact
15
15
  .map do |name, content|
16
16
  tag.meta(property: "og:#{name}", content: content)
17
17
  end,
@@ -38,14 +38,12 @@ module PagesCore
38
38
  end
39
39
 
40
40
  def default_open_graph_properties
41
- {
42
- type: "website",
41
+ { type: "website",
43
42
  site_name: PagesCore.config(:site_name),
44
43
  title: default_open_graph_title,
45
44
  image: (meta_image if meta_image?),
46
45
  description: default_open_graph_description,
47
- url: request.url
48
- }
46
+ url: request.url }
49
47
  end
50
48
  end
51
49
  end
@@ -54,7 +54,7 @@ module PagesCore
54
54
  ActiveSupport::Deprecation.warn(
55
55
  "Calling page_url without locale is deprecated"
56
56
  )
57
- [(opts[:locale] || @locale), page_or_locale]
57
+ [(opts[:locale] || content_locale), page_or_locale]
58
58
  end
59
59
 
60
60
  def paginated_section(opts)
@@ -8,22 +8,22 @@ import { AttachmentResource, Locale } from "../../types";
8
8
  import { useDraggable, Draggable } from "../drag";
9
9
 
10
10
  interface Record {
11
- id: number | null,
12
- attachment: AttachmentResource,
13
- uploading: boolean
11
+ id: number | null;
12
+ attachment: AttachmentResource;
13
+ uploading: boolean;
14
14
  }
15
15
 
16
16
  interface AttachmentProps {
17
- attributeName: string,
18
- placeholder: boolean,
19
- draggable: { record: Record },
20
- locale: string,
21
- locales: { [index: string]: Locale },
22
- deleteRecord: () => void,
23
- showEmbed: boolean,
24
- position: number,
25
- onUpdate: (localizations: Record<string, Record<string, string>>) => void,
26
- startDrag: (evt: Event, draggable: Draggable) => void
17
+ attributeName: string;
18
+ placeholder: boolean;
19
+ draggable: { record: Record };
20
+ locale: string;
21
+ locales: { [index: string]: Locale };
22
+ deleteRecord: () => void;
23
+ showEmbed: boolean;
24
+ position: number;
25
+ onUpdate: (localizations: Record<string, Record<string, string>>) => void;
26
+ startDrag: (evt: Event, draggable: Draggable) => void;
27
27
  }
28
28
 
29
29
  export default function Attachment(props: AttachmentProps) {
@@ -70,7 +70,8 @@ export default function Attachment(props: AttachmentProps) {
70
70
  attachment={attachment}
71
71
  locale={locale}
72
72
  locales={locales}
73
- onUpdate={props.onUpdate} />
73
+ onUpdate={props.onUpdate}
74
+ />
74
75
  );
75
76
  };
76
77
 
@@ -90,44 +91,46 @@ export default function Attachment(props: AttachmentProps) {
90
91
  }
91
92
 
92
93
  return (
93
- <div className={classes.join(" ")}
94
- {...listeners}>
95
- <input name={`${attributeName}[id]`}
96
- type="hidden" value={record.id || ""} />
97
- <input name={`${attributeName}[attachment_id]`}
98
- type="hidden" value={(attachment && attachment.id) || ""} />
99
- <input name={`${attributeName}[position]`}
100
- type="hidden" value={props.position} />
101
- {!uploading &&
102
- <div className="actions">
103
- <button onClick={editAttachment}>
104
- Edit
105
- </button>
106
- {props.showEmbed && (
107
- <button onClick={copyEmbed}>
108
- Embed
109
- </button>
110
- )}
111
- {props.deleteRecord && (
112
- <button onClick={deleteRecord}>
113
- Remove
114
- </button>
115
- )}
116
- </div>
117
- }
118
- {attachment &&
119
- <div className="attachment-info">
120
- <h3>
121
- <i className={`fa-solid fa-${icon} icon`} />
122
- {name() || <em>Untitled</em>}<br />
123
- </h3>
124
- {!uploading &&
125
- <a href={attachment.url}
126
- rel="noreferrer"
127
- target="_blank">{attachment.filename}</a>}
128
- {!uploading && description() &&
129
- <p dir={localeDir}>{description()}</p>}
130
- </div>}
94
+ <div className={classes.join(" ")} {...listeners}>
95
+ <input
96
+ name={`${attributeName}[id]`}
97
+ type="hidden"
98
+ value={record.id || ""}
99
+ />
100
+ <input
101
+ name={`${attributeName}[attachment_id]`}
102
+ type="hidden"
103
+ value={(attachment && attachment.id) || ""}
104
+ />
105
+ <input
106
+ name={`${attributeName}[position]`}
107
+ type="hidden"
108
+ value={props.position}
109
+ />
110
+ {!uploading && (
111
+ <div className="actions">
112
+ <button onClick={editAttachment}>Edit</button>
113
+ {props.showEmbed && <button onClick={copyEmbed}>Embed</button>}
114
+ {props.deleteRecord && <button onClick={deleteRecord}>Remove</button>}
115
+ </div>
116
+ )}
117
+ {attachment && (
118
+ <div className="attachment-info">
119
+ <h3>
120
+ <i className={`fa-solid fa-${icon} icon`} />
121
+ {name() || <em>Untitled</em>}
122
+ <br />
123
+ </h3>
124
+ {!uploading && (
125
+ <a href={attachment.url} rel="noreferrer" target="_blank">
126
+ {attachment.filename}
127
+ </a>
128
+ )}
129
+ {!uploading && description() && (
130
+ <p dir={localeDir}>{description()}</p>
131
+ )}
132
+ </div>
133
+ )}
131
134
  </div>
132
135
  );
133
136
  }
@@ -6,10 +6,10 @@ import { AttachmentResource, Locale } from "../../types";
6
6
  import { putJson } from "../../lib/request";
7
7
 
8
8
  interface AttachmentEditorProps {
9
- attachment: AttachmentResource,
10
- locale: string,
11
- locales: { [index: string]: Locale },
12
- onUpdate: (localizations: Record<string, Record<string, string>>) => void
9
+ attachment: AttachmentResource;
10
+ locale: string;
11
+ locales: { [index: string]: Locale };
12
+ onUpdate: (localizations: Record<string, Record<string, string>>) => void;
13
13
  }
14
14
 
15
15
  export default function AttachmentEditor(props: AttachmentEditorProps) {
@@ -18,19 +18,19 @@ export default function AttachmentEditor(props: AttachmentEditorProps) {
18
18
  const [locale, setLocale] = useState(props.locale);
19
19
  const [localizations, setLocalizations] = useState({
20
20
  name: attachment.name || {},
21
- description: attachment.description || {},
21
+ description: attachment.description || {}
22
22
  });
23
23
 
24
24
  const notice = useToastStore((state) => state.notice);
25
25
  const closeModal = useModalStore((state) => state.close);
26
26
 
27
- const updateLocalization = (name: "name" | "description") => (evt: ChangeEvent<HTMLInputElement>) => {
28
- setLocalizations({
29
- ...localizations,
30
- [name]: { ...localizations[name],
31
- [locale]: evt.target.value }
32
- });
33
- };
27
+ const updateLocalization =
28
+ (name: "name" | "description") => (evt: ChangeEvent<HTMLInputElement>) => {
29
+ setLocalizations({
30
+ ...localizations,
31
+ [name]: { ...localizations[name], [locale]: evt.target.value }
32
+ });
33
+ };
34
34
 
35
35
  const copyEmbedCode = (evt: Event) => {
36
36
  evt.preventDefault();
@@ -59,13 +59,12 @@ export default function AttachmentEditor(props: AttachmentEditorProps) {
59
59
  <form>
60
60
  {props.locales && Object.keys(locales).length > 1 && (
61
61
  <div className="field">
62
- <label>
63
- Locale
64
- </label>
65
- <select name="locale"
66
- value={locale}
67
- onChange={e => setLocale(e.target.value)}>
68
- {Object.keys(locales).map(key => (
62
+ <label>Locale</label>
63
+ <select
64
+ name="locale"
65
+ value={locale}
66
+ onChange={(e) => setLocale(e.target.value)}>
67
+ {Object.keys(locales).map((key) => (
69
68
  <option key={`locale-${key}`} value={key}>
70
69
  {locales[key].name}
71
70
  </option>
@@ -75,47 +74,43 @@ export default function AttachmentEditor(props: AttachmentEditorProps) {
75
74
  )}
76
75
  <div className="field">
77
76
  <label>Name</label>
78
- <input type="text"
79
- className="name"
80
- lang={locale}
81
- dir={inputDir}
82
- value={localizations.name[locale] || ""}
83
- onChange={updateLocalization("name")} />
77
+ <input
78
+ type="text"
79
+ className="name"
80
+ lang={locale}
81
+ dir={inputDir}
82
+ value={localizations.name[locale] || ""}
83
+ onChange={updateLocalization("name")}
84
+ />
84
85
  </div>
85
86
  <div className="field">
86
87
  <label>Description</label>
87
- <textarea className="description"
88
- value={localizations.description[locale] || ""}
89
- lang={locale}
90
- dir={inputDir}
91
- onChange={updateLocalization("description")} />
88
+ <textarea
89
+ className="description"
90
+ value={localizations.description[locale] || ""}
91
+ lang={locale}
92
+ dir={inputDir}
93
+ onChange={updateLocalization("description")}
94
+ />
92
95
  </div>
93
96
  <div className="field embed-code">
94
- <label>
95
- Embed code
96
- </label>
97
- <input type="text"
98
- value={`[attachment:${attachment.id}]`}
99
- disabled={true} />
100
- {copySupported() && (
101
- <button onClick={copyEmbedCode}>
102
- Copy
103
- </button>
104
- )}
97
+ <label>Embed code</label>
98
+ <input
99
+ type="text"
100
+ value={`[attachment:${attachment.id}]`}
101
+ disabled={true}
102
+ />
103
+ {copySupported() && <button onClick={copyEmbedCode}>Copy</button>}
105
104
  </div>
106
105
  <div className="field">
107
106
  <label>File</label>
108
- <a href={attachment.url}
109
- rel="noreferrer"
110
- target="_blank">{attachment.filename}</a>
107
+ <a href={attachment.url} rel="noreferrer" target="_blank">
108
+ {attachment.filename}
109
+ </a>
111
110
  </div>
112
111
  <div className="buttons">
113
- <button onClick={save}>
114
- Save
115
- </button>
116
- <button onClick={closeModal}>
117
- Cancel
118
- </button>
112
+ <button onClick={save}>Save</button>
113
+ <button onClick={closeModal}>Cancel</button>
119
114
  </div>
120
115
  </form>
121
116
  </div>
@@ -2,8 +2,7 @@ import React from "react";
2
2
 
3
3
  export default function Placeholder() {
4
4
  return (
5
- <div className="attachment drop-placeholder"
6
- key="file-placeholder">
5
+ <div className="attachment drop-placeholder" key="file-placeholder">
7
6
  Upload files here
8
7
  </div>
9
8
  );