pages_core 3.12.0 → 3.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/builds/fonts/661557ef.ttf +0 -0
  4. data/app/assets/builds/fonts/a18fc2d2.woff2 +0 -0
  5. data/app/assets/builds/fonts/b2c7b78f.woff2 +0 -0
  6. data/app/assets/builds/fonts/ceddc204.ttf +0 -0
  7. data/app/assets/builds/pages_core/admin-dist.js +60 -14
  8. data/app/assets/builds/pages_core/admin-dist.js.map +7 -0
  9. data/app/assets/builds/pages_core/admin.css +9272 -0
  10. data/app/assets/images/pages/admin/angle-down-solid.svg +1 -0
  11. data/app/assets/images/pages/admin/icon.svg +1 -0
  12. data/app/assets/stylesheets/pages_core/admin/components/archive.css +6 -0
  13. data/app/assets/stylesheets/{pages/admin/components/attachments.scss → pages_core/admin/components/attachments.css} +35 -28
  14. data/app/assets/stylesheets/{pages/admin.scss → pages_core/admin/components/base.css} +125 -123
  15. data/app/assets/stylesheets/pages_core/admin/components/forms.css +223 -0
  16. data/app/assets/stylesheets/{pages/admin/components/header.scss → pages_core/admin/components/header.css} +76 -46
  17. data/app/assets/stylesheets/{pages/admin/components/image_editor.scss → pages_core/admin/components/image_editor.css} +42 -31
  18. data/app/assets/stylesheets/{pages/admin/components/image_grid.scss → pages_core/admin/components/image_grid.css} +76 -64
  19. data/app/assets/stylesheets/{pages/admin/components/image_uploader.scss → pages_core/admin/components/image_uploader.css} +12 -12
  20. data/app/assets/stylesheets/{pages/admin/components/layout.scss → pages_core/admin/components/layout.css} +13 -9
  21. data/app/assets/stylesheets/pages_core/admin/components/links.css +40 -0
  22. data/app/assets/stylesheets/pages_core/admin/components/list_table.css +66 -0
  23. data/app/assets/stylesheets/{pages/admin/components/login.scss → pages_core/admin/components/login.css} +6 -5
  24. data/app/assets/stylesheets/{pages/admin/components/modal.scss → pages_core/admin/components/modal.css} +10 -12
  25. data/app/assets/stylesheets/{pages/admin/components/page_tree.scss → pages_core/admin/components/page_tree.css} +54 -55
  26. data/app/assets/stylesheets/{pages/admin/components/pagination.scss → pages_core/admin/components/pagination.css} +17 -17
  27. data/app/assets/stylesheets/pages_core/admin/components/search.css +27 -0
  28. data/app/assets/stylesheets/{pages/admin/components/sidebar.scss → pages_core/admin/components/sidebar.css} +8 -7
  29. data/app/assets/stylesheets/{pages/admin/components/tag_editor.scss → pages_core/admin/components/tag_editor.css} +10 -15
  30. data/app/assets/stylesheets/{pages/admin/components/textarea.scss → pages_core/admin/components/textarea.css} +1 -1
  31. data/app/assets/stylesheets/{pages/admin/components/toast.scss → pages_core/admin/components/toast.css} +5 -3
  32. data/app/assets/stylesheets/{pages/admin/components/toolbar.scss → pages_core/admin/components/toolbar.css} +56 -29
  33. data/app/assets/stylesheets/{pages/admin/controllers/pages.scss → pages_core/admin/controllers/pages.css} +69 -52
  34. data/app/assets/stylesheets/pages_core/admin/controllers/users.css +3 -0
  35. data/app/assets/stylesheets/pages_core/admin/vars.css +34 -0
  36. data/app/assets/stylesheets/pages_core/admin.postcss.css +9 -0
  37. data/app/controllers/admin/pages_controller.rb +12 -11
  38. data/app/controllers/concerns/pages_core/rss_controller.rb +17 -1
  39. data/app/controllers/pages_core/admin_controller.rb +6 -0
  40. data/app/controllers/pages_core/frontend/pages_controller.rb +9 -5
  41. data/app/controllers/pages_core/sitemaps_controller.rb +3 -5
  42. data/app/formatters/pages_core/image_embedder.rb +5 -27
  43. data/app/helpers/admin/calendars_helper.rb +8 -0
  44. data/app/helpers/admin/news_helper.rb +13 -0
  45. data/app/helpers/admin/pages_helper.rb +32 -0
  46. data/app/helpers/pages_core/admin/admin_helper.rb +11 -54
  47. data/app/helpers/pages_core/admin/deprecated_admin_helper.rb +40 -0
  48. data/app/helpers/pages_core/images_helper.rb +37 -0
  49. data/app/javascript/admin-dist.ts +2 -0
  50. data/app/javascript/components/Attachments/{Attachment.jsx → Attachment.tsx} +44 -35
  51. data/app/javascript/components/Attachments/{AttachmentEditor.jsx → AttachmentEditor.tsx} +23 -23
  52. data/app/javascript/components/{EditableImage.jsx → EditableImage.tsx} +28 -25
  53. data/app/javascript/components/{FileUploadButton.jsx → FileUploadButton.tsx} +15 -16
  54. data/app/javascript/components/ImageCropper/FocalPoint.tsx +94 -0
  55. data/app/javascript/components/ImageCropper/{Image.jsx → Image.tsx} +13 -14
  56. data/app/javascript/components/ImageCropper/{Toolbar.jsx → Toolbar.tsx} +19 -15
  57. data/app/javascript/components/ImageCropper/{useCrop.js → useCrop.ts} +80 -37
  58. data/app/javascript/components/{ImageCropper.jsx → ImageCropper.tsx} +17 -15
  59. data/app/javascript/components/ImageEditor/{Form.jsx → Form.tsx} +24 -23
  60. data/app/javascript/components/{ImageEditor.jsx → ImageEditor.tsx} +17 -15
  61. data/app/javascript/components/ImageGrid/{DragElement.jsx → DragElement.tsx} +12 -10
  62. data/app/javascript/components/ImageGrid/{GridImage.jsx → GridImage.tsx} +40 -30
  63. data/app/javascript/components/ImageGrid/{Placeholder.jsx → Placeholder.tsx} +5 -6
  64. data/app/javascript/components/ImageGrid.jsx +3 -4
  65. data/app/javascript/components/{ImageUploader.jsx → ImageUploader.tsx} +46 -41
  66. data/app/javascript/components/Modal.tsx +48 -0
  67. data/app/javascript/components/PageImages.tsx +28 -0
  68. data/app/javascript/components/{PageTreeDraggable.jsx → PageTree/Draggable.tsx} +79 -57
  69. data/app/javascript/components/{PageTreeNode.jsx → PageTree/Node.tsx} +86 -77
  70. data/app/javascript/components/PageTree/types.ts +15 -0
  71. data/app/javascript/components/PageTree.tsx +206 -0
  72. data/app/javascript/components/RichTextToolbarButton.tsx +17 -0
  73. data/app/javascript/components/TagEditor/{AddTagForm.jsx → AddTagForm.tsx} +9 -10
  74. data/app/javascript/components/TagEditor/{Tag.jsx → Tag.tsx} +8 -9
  75. data/app/javascript/components/{TagEditor.jsx → TagEditor.tsx} +12 -13
  76. data/app/javascript/components/Toast.tsx +61 -0
  77. data/app/javascript/components/drag/{draggedOrder.js → draggedOrder.ts} +22 -12
  78. data/app/javascript/components/drag/types.ts +28 -0
  79. data/app/javascript/components/drag/{useDragCollection.js → useDragCollection.ts} +40 -22
  80. data/app/javascript/components/drag/{useDragUploader.js → useDragUploader.ts} +34 -25
  81. data/app/javascript/components/drag/useDraggable.ts +21 -0
  82. data/app/javascript/components/{drag.js → drag.ts} +1 -0
  83. data/app/javascript/controllers/{EditPageController.js → EditPageController.ts} +3 -1
  84. data/app/javascript/controllers/{LoginController.js → LoginController.ts} +7 -3
  85. data/app/javascript/controllers/{MainController.js → MainController.ts} +19 -14
  86. data/app/javascript/{index.js → index.ts} +8 -7
  87. data/app/javascript/lib/{Tree.js → Tree.ts} +106 -85
  88. data/app/javascript/lib/{copyToClipboard.js → copyToClipboard.ts} +1 -1
  89. data/app/javascript/lib/{readyHandler.js → readyHandler.ts} +4 -2
  90. data/app/javascript/lib/{request.js → request.ts} +11 -5
  91. data/app/javascript/stores/useModalStore.ts +15 -0
  92. data/app/javascript/stores/useToastStore.ts +26 -0
  93. data/app/javascript/stores.ts +2 -0
  94. data/app/javascript/types.ts +30 -0
  95. data/app/mailers/admin_mailer.rb +1 -0
  96. data/app/models/invite.rb +8 -0
  97. data/app/policies/page_policy.rb +4 -0
  98. data/app/views/admin/calendars/_sidebar.html.erb +50 -0
  99. data/app/views/admin/calendars/show.html.erb +15 -53
  100. data/app/views/admin/invites/new.html.erb +2 -8
  101. data/app/views/admin/invites/show.html.erb +2 -4
  102. data/app/views/admin/news/_sidebar.html.erb +51 -0
  103. data/app/views/admin/news/index.html.erb +21 -56
  104. data/app/views/admin/pages/_list_item.html.erb +4 -22
  105. data/app/views/admin/pages/_search_bar.html.erb +12 -0
  106. data/app/views/admin/pages/deleted.html.erb +10 -8
  107. data/app/views/admin/pages/edit.html.erb +20 -11
  108. data/app/views/admin/pages/index.html.erb +10 -8
  109. data/app/views/admin/pages/new.html.erb +10 -14
  110. data/app/views/admin/pages/search.html.erb +54 -0
  111. data/app/views/admin/password_resets/show.html.erb +3 -5
  112. data/app/views/admin/users/deactivated.html.erb +6 -7
  113. data/app/views/admin/users/edit.html.erb +7 -9
  114. data/app/views/admin/users/index.html.erb +3 -6
  115. data/app/views/admin/users/login.html.erb +4 -5
  116. data/app/views/admin/users/new.html.erb +2 -4
  117. data/app/views/admin/users/new_password.html.erb +4 -5
  118. data/app/views/admin/users/show.html.erb +11 -9
  119. data/app/views/errors/401.html.erb +2 -1
  120. data/app/views/errors/403.html.erb +2 -1
  121. data/app/views/errors/404.html.erb +1 -3
  122. data/app/views/errors/405.html.erb +2 -1
  123. data/app/views/errors/422.html.erb +2 -1
  124. data/app/views/errors/500.html.erb +2 -3
  125. data/app/views/feeds/pages.rss.builder +3 -9
  126. data/app/views/layouts/admin/_header.html.erb +1 -2
  127. data/app/views/layouts/admin/_page_header.html.erb +4 -4
  128. data/app/views/layouts/admin.html.erb +3 -3
  129. data/app/views/layouts/errors.html.erb +127 -4
  130. data/config/routes.rb +1 -0
  131. data/lib/pages_core/configuration/pages.rb +0 -1
  132. data/lib/pages_core/engine.rb +4 -3
  133. data/lib/pages_core.rb +0 -1
  134. data/lib/rails/generators/pages_core/frontend/frontend_generator.rb +33 -17
  135. data/lib/rails/generators/pages_core/frontend/templates/application.html.erb +0 -1
  136. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/gridOverlay.ts +40 -0
  137. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/responsiveEmbeds.ts +68 -0
  138. data/lib/rails/generators/pages_core/frontend/templates/postcss.config.js +17 -0
  139. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.postcss.css +4 -0
  140. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.css +24 -0
  141. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/layout.css +21 -0
  142. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.css +5 -0
  143. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/animation.css +5 -0
  144. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.css +18 -0
  145. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/fonts.css +6 -0
  146. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/grid.css +65 -0
  147. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.css +131 -0
  148. data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +0 -3
  149. metadata +104 -255
  150. data/app/assets/images/pages/admin/icon.png +0 -0
  151. data/app/assets/images/pages/admin/image-editor-bg.png +0 -0
  152. data/app/assets/images/pages/admin/list-table-pin-blue.gif +0 -0
  153. data/app/assets/images/pages/admin/list-table-pin-disabled.gif +0 -0
  154. data/app/assets/images/pages/admin/list-table-pin-green.gif +0 -0
  155. data/app/assets/images/pages/admin/list-table-pin-red.gif +0 -0
  156. data/app/assets/images/pages/admin/list-table-pin-yellow.gif +0 -0
  157. data/app/assets/images/pages/admin/loading-modal.gif +0 -0
  158. data/app/assets/images/pages/feed-icon-14x14.png +0 -0
  159. data/app/assets/stylesheets/pages/admin/components/archive.scss +0 -6
  160. data/app/assets/stylesheets/pages/admin/components/buttons.scss +0 -23
  161. data/app/assets/stylesheets/pages/admin/components/forms.scss +0 -169
  162. data/app/assets/stylesheets/pages/admin/components/links.scss +0 -43
  163. data/app/assets/stylesheets/pages/admin/components/list_table.scss +0 -61
  164. data/app/assets/stylesheets/pages/admin/controllers/users.scss +0 -3
  165. data/app/assets/stylesheets/pages/admin/mixins/breakpoints.scss +0 -21
  166. data/app/assets/stylesheets/pages/admin/mixins/clearfix.scss +0 -7
  167. data/app/assets/stylesheets/pages/admin/mixins/gradients.scss +0 -7
  168. data/app/assets/stylesheets/pages/admin/vars.scss +0 -30
  169. data/app/assets/stylesheets/pages/errors.css +0 -128
  170. data/app/javascript/admin-dist.js +0 -2
  171. data/app/javascript/components/ImageCropper/FocalPoint.jsx +0 -93
  172. data/app/javascript/components/Modal.jsx +0 -59
  173. data/app/javascript/components/PageImages.jsx +0 -25
  174. data/app/javascript/components/PageTree.jsx +0 -196
  175. data/app/javascript/components/RichTextToolbarButton.jsx +0 -20
  176. data/app/javascript/components/Toast.jsx +0 -72
  177. data/app/javascript/components/drag/useDraggable.js +0 -17
  178. data/app/javascript/stores/ModalStore.jsx +0 -12
  179. data/app/javascript/stores/ToastStore.jsx +0 -14
  180. data/app/javascript/stores.js +0 -2
  181. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/GridOverlay.js +0 -66
  182. data/lib/rails/generators/pages_core/frontend/templates/javascript/lib/ResponsiveEmbeds.js +0 -72
  183. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/application.sass.scss +0 -15
  184. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/components/base.scss +0 -12
  185. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/config.scss +0 -26
  186. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/breakpoints.scss +0 -42
  187. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/clearfix.scss +0 -7
  188. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/fonts.scss +0 -32
  189. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid.scss +0 -168
  190. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/framework/grid_overlay.scss +0 -44
  191. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/colors.scss +0 -8
  192. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/global/typography.scss +0 -90
  193. data/lib/rails/generators/pages_core/frontend/templates/stylesheets/vendor/normalize.css +0 -349
  194. data/vendor/assets/stylesheets/ReactCrop.css +0 -167
  195. /data/app/assets/stylesheets/{pages/admin/components/tabs.scss → pages_core/admin/components/tabs.css} +0 -0
  196. /data/app/javascript/components/Attachments/{Placeholder.jsx → Placeholder.tsx} +0 -0
  197. /data/app/javascript/components/ImageGrid/{FilePlaceholder.jsx → FilePlaceholder.tsx} +0 -0
  198. /data/app/javascript/{components.js → components.ts} +0 -0
  199. /data/app/javascript/{hooks.js → hooks.ts} +0 -0
@@ -1,7 +1,15 @@
1
- import React from "react";
2
- import PropTypes from "prop-types";
1
+ import React, { RefObject } from "react";
3
2
 
4
- export default function DragElement(props) {
3
+ import { ImageResource } from "../../types";
4
+ import { DragState } from "../drag";
5
+
6
+ interface DragElementProps {
7
+ container: RefObject<HTMLDivElement>,
8
+ draggable: string | { record: { image: ImageResource, src?: string } },
9
+ dragState: DragState
10
+ }
11
+
12
+ export default function DragElement(props: DragElementProps) {
5
13
  const { draggable, dragState, container } = props;
6
14
 
7
15
  if (draggable === "Files") {
@@ -15,16 +23,10 @@ export default function DragElement(props) {
15
23
  };
16
24
  return (
17
25
  <div className="drag-image" style={translateStyle}>
18
- {draggable.record.image && (
26
+ {"record" in draggable && draggable.record.image && (
19
27
  <img src={draggable.record.src || draggable.record.image.thumbnail_url} />
20
28
  )}
21
29
  </div>
22
30
  );
23
31
  }
24
32
  }
25
-
26
- DragElement.propTypes = {
27
- draggable: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
28
- dragState: PropTypes.object,
29
- container: PropTypes.object
30
- };
@@ -1,17 +1,41 @@
1
1
  import React, { useEffect, useState } from "react";
2
- import PropTypes from "prop-types";
3
2
  import copyToClipboard from "../../lib/copyToClipboard";
4
3
  import EditableImage from "../EditableImage";
5
- import ToastStore from "../../stores/ToastStore";
4
+ import useToastStore from "../../stores/useToastStore";
5
+ import { ImageResource, Locale } from "../../types";
6
6
  import Placeholder from "./Placeholder";
7
7
 
8
8
  import { useDraggable } from "../drag";
9
9
 
10
- export default function GridImage(props) {
10
+ interface Record {
11
+ id: number | null,
12
+ image: ImageResource,
13
+ src: string | null,
14
+ file: File | null
15
+ }
16
+
17
+ interface GridImageProps {
18
+ draggable: { handle: string, record: Record }
19
+ attributeName: string,
20
+ locale: string,
21
+ locales: { [index: string]: Locale },
22
+ placeholder: boolean,
23
+ enablePrimary: boolean,
24
+ showEmbed: boolean,
25
+ primary: boolean,
26
+ position: number,
27
+ deleteImage: () => void,
28
+ startDrag: (evt: Event, draggable: Draggable) => void,
29
+ onUpdate: (newImage: ImageResource, src: string) => void
30
+ }
31
+
32
+ export default function GridImage(props: GridImageProps) {
11
33
  const { attributeName, draggable } = props;
12
34
  const record = draggable.record;
13
35
  const image = record.image;
14
36
 
37
+ const notice = useToastStore((state) => state.notice);
38
+
15
39
  const [src, setSrc] = useState(record.src || null);
16
40
 
17
41
  const dragAttrs = useDraggable(draggable, props.startDrag);
@@ -24,22 +48,20 @@ export default function GridImage(props) {
24
48
  }
25
49
  }, []);
26
50
 
27
- const copyEmbed = (evt) => {
51
+ const copyEmbed = (evt: Event) => {
28
52
  evt.preventDefault();
29
53
  copyToClipboard(`[image:${image.id}]`);
30
- ToastStore.dispatch({
31
- type: "NOTICE", message: "Embed code copied to clipboard"
32
- });
54
+ notice("Embed code copied to clipboard");
33
55
  };
34
56
 
35
- const deleteImage = (evt) => {
57
+ const deleteImage = (evt: Event) => {
36
58
  evt.preventDefault();
37
59
  if (props.deleteImage) {
38
60
  props.deleteImage();
39
61
  }
40
62
  };
41
63
 
42
- let classes = ["grid-image"];
64
+ const classes = ["grid-image"];
43
65
  if (props.placeholder) {
44
66
  classes.push("placeholder");
45
67
  }
@@ -64,13 +86,15 @@ export default function GridImage(props) {
64
86
  <Placeholder src={src} />}
65
87
  {image &&
66
88
  <>
67
- <EditableImage image={image}
68
- src={src || image.thumbnail_url}
69
- width={250}
70
- caption={true}
71
- locale={props.locale}
72
- locales={props.locales}
73
- onUpdate={props.onUpdate} />
89
+ <EditableImage
90
+ image={image}
91
+ key={props.placeholder ? "placeholder" : draggable.handle}
92
+ src={src || image.thumbnail_url}
93
+ width={250}
94
+ caption={true}
95
+ locale={props.locale}
96
+ locales={props.locales}
97
+ onUpdate={props.onUpdate} />
74
98
  <div className="actions">
75
99
  {props.showEmbed && (
76
100
  <button onClick={copyEmbed}>
@@ -87,17 +111,3 @@ export default function GridImage(props) {
87
111
  </div>
88
112
  );
89
113
  }
90
- GridImage.propTypes = {
91
- draggable: PropTypes.object,
92
- deleteImage: PropTypes.func,
93
- startDrag: PropTypes.func,
94
- locale: PropTypes.string,
95
- locales: PropTypes.object,
96
- onUpdate: PropTypes.func,
97
- attributeName: PropTypes.string,
98
- placeholder: PropTypes.bool,
99
- enablePrimary: PropTypes.bool,
100
- showEmbed: PropTypes.bool,
101
- primary: PropTypes.bool,
102
- position: PropTypes.number,
103
- };
@@ -1,7 +1,10 @@
1
1
  import React from "react";
2
- import PropTypes from "prop-types";
3
2
 
4
- export default function Placeholder(props) {
3
+ interface PlaceholderProps {
4
+ src: string
5
+ }
6
+
7
+ export default function Placeholder(props: PlaceholderProps) {
5
8
  if (props.src) {
6
9
  return (
7
10
  <div className="temp-image">
@@ -17,7 +20,3 @@ export default function Placeholder(props) {
17
20
  );
18
21
  }
19
22
  }
20
-
21
- Placeholder.propTypes = {
22
- src: PropTypes.string
23
- };
@@ -4,7 +4,7 @@ import FileUploadButton from "./FileUploadButton";
4
4
  import DragElement from "./ImageGrid/DragElement";
5
5
  import FilePlaceholder from "./ImageGrid/FilePlaceholder";
6
6
  import GridImage from "./ImageGrid/GridImage";
7
- import ToastStore from "../stores/ToastStore";
7
+ import useToastStore from "../stores/useToastStore";
8
8
  import { post } from "../lib/request";
9
9
 
10
10
  import { createDraggable,
@@ -49,6 +49,7 @@ export default function ImageGrid(props) {
49
49
  const primary = useDragCollection(initPrimary);
50
50
  const images = useDragCollection(initImages);
51
51
  const [deleted, setDeleted] = useState([]);
52
+ const error = useToastStore((state) => state.error);
52
53
 
53
54
  const containerRef = useRef();
54
55
 
@@ -99,9 +100,7 @@ export default function ImageGrid(props) {
99
100
  post("/admin/images.json", data)
100
101
  .then(json => {
101
102
  if (json.status === "error") {
102
- ToastStore.dispatch({
103
- type: "ERROR", message: "Error uploading image: " + json.error
104
- });
103
+ error("Error uploading image: " + json.error);
105
104
  dispatchAll({ type: "remove", payload: draggable });
106
105
  } else {
107
106
  dispatchAll({
@@ -1,12 +1,25 @@
1
1
  import React, { useState } from "react";
2
- import PropTypes from "prop-types";
3
2
  import EditableImage from "./EditableImage";
4
3
  import FileUploadButton from "./FileUploadButton";
5
- import ToastStore from "../stores/ToastStore";
4
+ import useToastStore from "../stores/useToastStore";
5
+ import { ImageResource, Locale } from "../types";
6
6
  import { post } from "../lib/request";
7
7
 
8
- function getFiles(dt) {
9
- var files = [];
8
+ type ImageResponse = ImageResource | { status: "error", error: string }
9
+
10
+ interface ImageUploaderProps {
11
+ locale: string,
12
+ locales: { [index: string]: Locale },
13
+ image: ImageResource,
14
+ src: string,
15
+ width: number,
16
+ caption: boolean,
17
+ attr: string,
18
+ alternative: string
19
+ }
20
+
21
+ function getFiles(dt: DataTransfer): File[] {
22
+ const files: File[] = [];
10
23
  if (dt.items) {
11
24
  for (let i = 0; i < dt.items.length; i++) {
12
25
  if (dt.items[i].kind == "file") {
@@ -21,13 +34,14 @@ function getFiles(dt) {
21
34
  return files;
22
35
  }
23
36
 
24
- export default function ImageUploader(props) {
37
+ export default function ImageUploader(props: ImageUploaderProps) {
25
38
  const [uploading, setUploading] = useState(false);
26
39
  const [dragover, setDragover] = useState(false);
27
40
  const [image, setImage] = useState(props.image);
28
41
  const [src, setSrc] = useState(props.src);
42
+ const error = useToastStore((state) => state.error);
29
43
 
30
- const handleDragOver = (evt) => {
44
+ const handleDragOver = (evt: Event) => {
31
45
  evt.preventDefault();
32
46
  setDragover(true);
33
47
  };
@@ -36,39 +50,44 @@ export default function ImageUploader(props) {
36
50
  setDragover(false);
37
51
  };
38
52
 
39
- const handleDragEnd = (evt) => {
40
- if (evt.dataTransfer.items) {
41
- for (var i = 0; i < evt.dataTransfer.items.length; i++) {
42
- evt.dataTransfer.items.remove(i);
53
+ const handleDragEnd = (evt: Event) => {
54
+ if ("dataTransfer" in evt) {
55
+ if ("items" in evt.dataTransfer && "remove" in evt.dataTransfer.items) {
56
+ for (let i = 0; i < evt.dataTransfer.items.length; i++) {
57
+ evt.dataTransfer.items.remove(i);
58
+ }
59
+ } else if ("clearData" in evt.dataTransfer) {
60
+ evt.dataTransfer.clearData();
43
61
  }
44
- } else {
45
- evt.dataTransfer.clearData();
46
62
  }
47
63
  setDragover(false);
48
64
  };
49
65
 
50
- const handleDrop = (evt) => {
51
- let files = getFiles(evt.dataTransfer);
66
+ const handleDrop = (evt: Event) => {
67
+ let files: File[] = [];
68
+ if ("dataTransfer" in evt) {
69
+ files = getFiles(evt.dataTransfer);
70
+ }
52
71
  evt.preventDefault();
53
72
  if (files.length > 0) {
54
73
  uploadImage(files[0]);
55
74
  }
56
75
  };
57
76
 
58
- const handleRemove = (evt) => {
77
+ const handleRemove = (evt: Event) => {
59
78
  evt.preventDefault();
60
79
  setImage(null);
61
80
  setSrc(null);
62
81
  };
63
82
 
64
- const receiveFiles = (files) => {
83
+ const receiveFiles = (files: File[]) => {
65
84
  if (files.length > 0) {
66
85
  uploadImage(files[0]);
67
86
  }
68
87
  };
69
88
 
70
- const uploadImage = (file) => {
71
- let validTypes = ["image/gif",
89
+ const uploadImage = (file: File) => {
90
+ const validTypes = ["image/gif",
72
91
  "image/jpeg",
73
92
  "image/pjpeg",
74
93
  "image/png",
@@ -80,10 +99,10 @@ export default function ImageUploader(props) {
80
99
  return;
81
100
  }
82
101
 
83
- let locale = props.locale;
84
- let locales = props.locales ? Object.keys(props.locales) : [locale];
102
+ const locale = props.locale;
103
+ const locales = props.locales ? Object.keys(props.locales) : [locale];
85
104
 
86
- let data = new FormData();
105
+ const data = new FormData();
87
106
 
88
107
  setImage(null);
89
108
  setSrc(null);
@@ -95,22 +114,19 @@ export default function ImageUploader(props) {
95
114
  data.append(`image[alternative][${l}]`, (props.alternative || ""));
96
115
  });
97
116
 
98
- post("/admin/images.json", data)
99
- .then(response => {
117
+ void post("/admin/images.json", data)
118
+ .then((response: ImageResponse) => {
100
119
  setUploading(false);
101
- if (response.status === "error") {
102
- ToastStore.dispatch({
103
- type: "ERROR",
104
- message: "Error uploading image: " + response.error
105
- });
106
- } else {
120
+ if ("status" in response && response.status === "error") {
121
+ error(`Error uploading image: ${response.error}`);
122
+ } else if ("thumbnail_url" in response) {
107
123
  setSrc(response.thumbnail_url);
108
124
  setImage(response);
109
125
  }
110
126
  });
111
127
  };
112
128
 
113
- let classes = ["image-uploader"];
129
+ const classes = ["image-uploader"];
114
130
  if (uploading) {
115
131
  classes.push("uploading");
116
132
  } else if (dragover) {
@@ -158,14 +174,3 @@ export default function ImageUploader(props) {
158
174
  </div>
159
175
  );
160
176
  }
161
-
162
- ImageUploader.propTypes = {
163
- locale: PropTypes.string,
164
- locales: PropTypes.object,
165
- image: PropTypes.object,
166
- src: PropTypes.string,
167
- width: PropTypes.number,
168
- caption: PropTypes.bool,
169
- attr: PropTypes.string,
170
- alternative: PropTypes.string
171
- };
@@ -0,0 +1,48 @@
1
+ import React, { useEffect } from "react";
2
+
3
+ import useModalStore from "../stores/useModalStore";
4
+
5
+ export default function Modal() {
6
+ const component = useModalStore((state) => state.component);
7
+ const close = useModalStore((state) => state.close);
8
+
9
+ const handleClose = (evt: Event) => {
10
+ evt.stopPropagation();
11
+ evt.preventDefault();
12
+ close();
13
+ };
14
+
15
+ const handleKeypress = (evt: KeyboardEvent) => {
16
+ if (component && (evt.key == "Escape" || evt.keyCode === 27)) {
17
+ handleClose(evt);
18
+ }
19
+ };
20
+
21
+ useEffect(() => {
22
+ if (component) {
23
+ document.body.classList.add("modal");
24
+ } else {
25
+ document.body.classList.remove("modal");
26
+ }
27
+ }, [component]);
28
+
29
+ useEffect(() => {
30
+ window.addEventListener("keypress", handleKeypress);
31
+ return () => {
32
+ window.removeEventListener("keypress", handleKeypress);
33
+ };
34
+ }, []);
35
+
36
+ if (component) {
37
+ return (
38
+ <div className="modal-wrapper open">
39
+ <div className="background" onClick={handleClose} />
40
+ <div className="modal">
41
+ {component}
42
+ </div>
43
+ </div>
44
+ );
45
+ } else {
46
+ return (<div className="modal-wrapper"></div>);
47
+ }
48
+ }
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import { ImageResource, Locale } from "../types";
3
+ import ImageGrid from "./ImageGrid";
4
+
5
+ interface PageImage {
6
+ id: number | null,
7
+ image: ImageResource
8
+ }
9
+
10
+ interface PageImagesProps {
11
+ locale: string,
12
+ locales: { [index: string]: Locale },
13
+ records: PageImage[]
14
+ }
15
+
16
+ export default function PageImages(props: PageImagesProps) {
17
+ return (
18
+ <div className="page-images">
19
+ <ImageGrid attribute="page[page_images_attributes]"
20
+ primaryAttribute="page[image_id]"
21
+ enablePrimary={true}
22
+ showEmbed={true}
23
+ locale={props.locale}
24
+ locales={props.locales}
25
+ records={props.records} />
26
+ </div>
27
+ );
28
+ }