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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/assets/builds/pages_core/admin-dist.js +8 -43
- data/app/assets/builds/pages_core/admin-dist.js.map +4 -4
- data/app/assets/builds/pages_core/admin.css +264 -133
- data/app/assets/stylesheets/pages_core/admin/components/attachments.css +3 -4
- data/app/assets/stylesheets/pages_core/admin/components/forms.css +17 -16
- data/app/assets/stylesheets/pages_core/admin/components/image_editor.css +8 -4
- data/app/assets/stylesheets/pages_core/admin/components/image_grid.css +1 -1
- data/app/assets/stylesheets/pages_core/admin/components/list_table.css +11 -3
- data/app/assets/stylesheets/pages_core/admin/components/modal.css +9 -5
- data/app/assets/stylesheets/pages_core/admin/components/page_tree.css +5 -1
- data/app/assets/stylesheets/pages_core/admin/components/toast.css +2 -2
- data/app/assets/stylesheets/pages_core/admin/controllers/pages.css +4 -2
- data/app/assets/stylesheets/pages_core/admin/vars.css +2 -1
- data/app/controllers/admin/calendars_controller.rb +2 -2
- data/app/controllers/admin/categories_controller.rb +3 -3
- data/app/controllers/admin/news_controller.rb +6 -6
- data/app/controllers/admin/pages_controller.rb +12 -11
- data/app/controllers/admin/users_controller.rb +1 -1
- data/app/controllers/concerns/pages_core/preview_pages_controller.rb +15 -17
- data/app/controllers/pages_core/admin_controller.rb +2 -2
- data/app/controllers/pages_core/base_controller.rb +1 -8
- data/app/controllers/pages_core/frontend/pages_controller.rb +13 -5
- data/app/controllers/pages_core/frontend_controller.rb +12 -7
- data/app/helpers/admin/menu_helper.rb +2 -0
- data/app/helpers/admin/pages_helper.rb +1 -4
- data/app/helpers/pages_core/admin/admin_helper.rb +0 -1
- data/app/helpers/pages_core/admin/content_tabs_helper.rb +9 -2
- data/app/helpers/pages_core/application_helper.rb +2 -3
- data/app/helpers/pages_core/frontend_helper.rb +1 -1
- data/app/helpers/pages_core/head_tags_helper.rb +15 -46
- data/app/helpers/pages_core/images_helper.rb +76 -21
- data/app/helpers/pages_core/locales_helper.rb +9 -0
- data/app/helpers/pages_core/open_graph_tags_helper.rb +3 -5
- data/app/helpers/pages_core/page_path_helper.rb +1 -1
- data/app/javascript/components/Attachments/Attachment.tsx +55 -52
- data/app/javascript/components/Attachments/AttachmentEditor.tsx +45 -50
- data/app/javascript/components/Attachments/Placeholder.tsx +1 -2
- data/app/javascript/components/Attachments.jsx +69 -57
- data/app/javascript/components/DateRangeSelect.jsx +94 -54
- data/app/javascript/components/EditableImage.tsx +20 -16
- data/app/javascript/components/FileUploadButton.tsx +12 -12
- data/app/javascript/components/ImageCropper/FocalPoint.tsx +22 -20
- data/app/javascript/components/ImageCropper/Image.tsx +20 -16
- data/app/javascript/components/ImageCropper/Toolbar.tsx +35 -27
- data/app/javascript/components/ImageCropper/useCrop.ts +105 -91
- data/app/javascript/components/ImageCropper.tsx +34 -25
- data/app/javascript/components/ImageEditor/Form.tsx +32 -43
- data/app/javascript/components/ImageEditor.tsx +29 -21
- data/app/javascript/components/ImageGrid/DragElement.tsx +6 -4
- data/app/javascript/components/ImageGrid/GridImage.tsx +56 -52
- data/app/javascript/components/ImageGrid/Placeholder.tsx +1 -1
- data/app/javascript/components/ImageGrid.jsx +132 -101
- data/app/javascript/components/ImageUploader.tsx +59 -55
- data/app/javascript/components/Modal.tsx +2 -4
- data/app/javascript/components/PageDates.jsx +25 -20
- data/app/javascript/components/PageFiles.jsx +7 -5
- data/app/javascript/components/PageImages.tsx +9 -7
- data/app/javascript/components/PageTree/Draggable.tsx +46 -40
- data/app/javascript/components/PageTree/Node.tsx +111 -95
- data/app/javascript/components/PageTree/types.ts +9 -9
- data/app/javascript/components/PageTree.tsx +44 -29
- data/app/javascript/components/RichTextArea.jsx +51 -37
- data/app/javascript/components/RichTextToolbarButton.tsx +8 -5
- data/app/javascript/components/TagEditor/AddTagForm.tsx +11 -10
- data/app/javascript/components/TagEditor/Tag.tsx +10 -8
- data/app/javascript/components/TagEditor.tsx +15 -10
- data/app/javascript/components/Toast.tsx +3 -7
- data/app/javascript/components/drag/draggedOrder.ts +16 -15
- data/app/javascript/components/drag/types.ts +12 -12
- data/app/javascript/components/drag/useDragCollection.ts +36 -42
- data/app/javascript/components/drag/useDragUploader.ts +3 -2
- data/app/javascript/components/drag.ts +5 -4
- data/app/javascript/controllers/LoginController.ts +0 -1
- data/app/javascript/controllers/MainController.ts +6 -2
- data/app/javascript/controllers/PageOptionsController.js +7 -2
- data/app/javascript/features/RichText.tsx +9 -7
- data/app/javascript/index.ts +5 -3
- data/app/javascript/lib/Tree.ts +27 -24
- data/app/javascript/lib/copyToClipboard.ts +5 -4
- data/app/javascript/lib/readyHandler.ts +4 -4
- data/app/javascript/lib/request.ts +7 -3
- data/app/javascript/stores/useModalStore.ts +3 -3
- data/app/javascript/stores/useToastStore.ts +14 -12
- data/app/javascript/types.ts +22 -22
- data/app/models/concerns/pages_core/page_model/templateable.rb +1 -1
- data/app/views/admin/calendars/show.html.erb +1 -1
- data/app/views/admin/news/index.html.erb +1 -1
- data/app/views/admin/pages/_edit_files.html.erb +1 -1
- data/app/views/admin/pages/_edit_images.html.erb +1 -1
- data/app/views/admin/pages/_list_item.html.erb +1 -1
- data/app/views/admin/pages/_search_bar.html.erb +1 -1
- data/app/views/admin/pages/deleted.html.erb +2 -2
- data/app/views/admin/pages/edit.html.erb +3 -3
- data/app/views/admin/pages/index.html.erb +4 -4
- data/app/views/admin/pages/new.html.erb +1 -1
- data/app/views/admin/pages/search.html.erb +3 -3
- data/app/views/feeds/pages.rss.builder +2 -2
- data/app/views/layouts/admin/_page_header.html.erb +4 -4
- data/app/views/layouts/admin.html.erb +1 -2
- data/config/locales/en.yml +1 -0
- data/lib/pages_core/pages_plugin.rb +5 -3
- data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +15 -13
- data/lib/tasks/pages/reports.rake +26 -0
- metadata +32 -4
- data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +0 -40
- data/app/views/pages_core/_google_analytics.html.erb +0 -8
|
@@ -10,13 +10,10 @@ module PagesCore
|
|
|
10
10
|
if args.any?
|
|
11
11
|
@document_title = args.first
|
|
12
12
|
else
|
|
13
|
-
safe_join(
|
|
14
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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],
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
@@ -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
|
-
.
|
|
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
|
|
@@ -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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<input
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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>
|