pages_core 3.12.0 → 3.12.2

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 (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
+ }