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
@@ -5,10 +5,12 @@ import Placeholder from "./Attachments/Placeholder";
5
5
  import FileUploadButton from "./FileUploadButton";
6
6
  import { post } from "../lib/request";
7
7
 
8
- import { createDraggable,
9
- draggedOrder,
10
- useDragCollection,
11
- useDragUploader } from "./drag";
8
+ import {
9
+ createDraggable,
10
+ draggedOrder,
11
+ useDragCollection,
12
+ useDragUploader
13
+ } from "./drag";
12
14
 
13
15
  function filenameToName(str) {
14
16
  return str.replace(/\.[\w\d]+$/, "").replace(/_/g, " ");
@@ -16,18 +18,20 @@ function filenameToName(str) {
16
18
 
17
19
  export default function Attachments(props) {
18
20
  const collection = useDragCollection(props.records);
19
- const locales = props.locales && props.locales.length > 0 ?
20
- Object.keys(props.locales) : [props.locale];
21
+ const locales =
22
+ props.locales && props.locales.length > 0
23
+ ? Object.keys(props.locales)
24
+ : [props.locale];
21
25
  const [deleted, setDeleted] = useState([]);
22
26
 
23
27
  const uploadAttachment = (file) => {
24
28
  let name = {};
25
- locales.forEach((l) => name[l] = file.name);
29
+ locales.forEach((l) => (name[l] = file.name));
26
30
 
27
- const draggable = createDraggable(
28
- { attachment: { filename: file.name, name: name },
29
- uploading: true }
30
- );
31
+ const draggable = createDraggable({
32
+ attachment: { filename: file.name, name: name },
33
+ uploading: true
34
+ });
31
35
 
32
36
  let data = new FormData();
33
37
 
@@ -36,14 +40,15 @@ export default function Attachments(props) {
36
40
  data.append(`attachment[name][${l}]`, filenameToName(file.name));
37
41
  });
38
42
 
39
- post("/admin/attachments.json", data)
40
- .then(json => {
41
- collection.dispatch({
42
- type: "update",
43
- payload: { ...draggable,
44
- record: { attachment: json, uploading: false } }
45
- });
43
+ post("/admin/attachments.json", data).then((json) => {
44
+ collection.dispatch({
45
+ type: "update",
46
+ payload: {
47
+ ...draggable,
48
+ record: { attachment: json, uploading: false }
49
+ }
46
50
  });
51
+ });
47
52
 
48
53
  return draggable;
49
54
  };
@@ -51,7 +56,7 @@ export default function Attachments(props) {
51
56
  const receiveFiles = (files) => {
52
57
  collection.dispatch({
53
58
  type: "append",
54
- payload: files.map(f => uploadAttachment(f))
59
+ payload: files.map((f) => uploadAttachment(f))
55
60
  });
56
61
  };
57
62
 
@@ -62,17 +67,21 @@ export default function Attachments(props) {
62
67
  });
63
68
  collection.dispatch({
64
69
  type: "insertFiles",
65
- payload: files.map(f => uploadAttachment(f))
70
+ payload: files.map((f) => uploadAttachment(f))
66
71
  });
67
72
  };
68
73
 
69
- const [dragState,
70
- dragStart,
71
- listeners] = useDragUploader([collection], dragEnd);
74
+ const [dragState, dragStart, listeners] = useDragUploader(
75
+ [collection],
76
+ dragEnd
77
+ );
72
78
 
73
79
  const position = (record) => {
74
- return [...collection.draggables.map(d => d.record),
75
- ...deleted].indexOf(record) + 1;
80
+ return (
81
+ [...collection.draggables.map((d) => d.record), ...deleted].indexOf(
82
+ record
83
+ ) + 1
84
+ );
76
85
  };
77
86
 
78
87
  const attrName = (record) => {
@@ -102,21 +111,23 @@ export default function Attachments(props) {
102
111
  const { dragging } = dragState;
103
112
 
104
113
  if (draggable === "Files") {
105
- return (<Placeholder key="placeholder" />);
114
+ return <Placeholder key="placeholder" />;
106
115
  }
107
116
 
108
117
  return (
109
- <Attachment key={draggable.handle}
110
- draggable={draggable}
111
- locale={props.locale}
112
- locales={props.locales}
113
- showEmbed={props.showEmbed}
114
- startDrag={dragStart}
115
- position={position(draggable.record)}
116
- onUpdate={update(draggable)}
117
- deleteRecord={remove(draggable)}
118
- attributeName={attrName(draggable.record)}
119
- placeholder={dragging && dragging == draggable} />
118
+ <Attachment
119
+ key={draggable.handle}
120
+ draggable={draggable}
121
+ locale={props.locale}
122
+ locales={props.locales}
123
+ showEmbed={props.showEmbed}
124
+ startDrag={dragStart}
125
+ position={position(draggable.record)}
126
+ onUpdate={update(draggable)}
127
+ deleteRecord={remove(draggable)}
128
+ attributeName={attrName(draggable.record)}
129
+ placeholder={dragging && dragging == draggable}
130
+ />
120
131
  );
121
132
  };
122
133
 
@@ -128,30 +139,31 @@ export default function Attachments(props) {
128
139
  }
129
140
 
130
141
  return (
131
- <div className={classes.join(" ")}
132
- ref={collection.ref}
133
- {...listeners}>
134
- <div className="files">
135
- {dragOrder.map(d => attachment(d))}
136
- </div>
142
+ <div className={classes.join(" ")} ref={collection.ref} {...listeners}>
143
+ <div className="files">{dragOrder.map((d) => attachment(d))}</div>
137
144
  <div className="deleted">
138
- {deleted.map(r =>
145
+ {deleted.map((r) => (
139
146
  <span className="deleted-attachment" key={r.id}>
140
- <input name={`${attrName(r)}[id]`}
141
- type="hidden"
142
- value={r.id} />
143
- <input name={`${attrName(r)}[attachment_id]`}
144
- type="hidden"
145
- value={(r.attachment && r.attachment.id) || ""} />
146
- <input name={`${attrName(r)}[_destroy]`}
147
- type="hidden"
148
- value={true} />
149
- </span>)}
147
+ <input name={`${attrName(r)}[id]`} type="hidden" value={r.id} />
148
+ <input
149
+ name={`${attrName(r)}[attachment_id]`}
150
+ type="hidden"
151
+ value={(r.attachment && r.attachment.id) || ""}
152
+ />
153
+ <input
154
+ name={`${attrName(r)}[_destroy]`}
155
+ type="hidden"
156
+ value={true}
157
+ />
158
+ </span>
159
+ ))}
150
160
  </div>
151
161
  <div className="drop-target">
152
- <FileUploadButton multiple={true}
153
- multiline={true}
154
- callback={receiveFiles} />
162
+ <FileUploadButton
163
+ multiple={true}
164
+ multiline={true}
165
+ callback={receiveFiles}
166
+ />
155
167
  </div>
156
168
  </div>
157
169
  );
@@ -6,9 +6,9 @@ export default class DateRangeSelect extends React.Component {
6
6
  super(props);
7
7
  this.state = {
8
8
  startsAt: this.parseDate(props.startsAt) || this.defaultDate(),
9
- endsAt: this.parseDate(props.endsAt) || this.defaultDate(60),
9
+ endsAt: this.parseDate(props.endsAt) || this.defaultDate(60),
10
10
  startTime: "",
11
- endTime: ""
11
+ endTime: ""
12
12
  };
13
13
  this.state.startTime = this.timeToString(this.state.startsAt);
14
14
  this.state.endTime = this.timeToString(this.state.endsAt);
@@ -33,8 +33,9 @@ export default class DateRangeSelect extends React.Component {
33
33
  defaultDate(offset = 0) {
34
34
  let coeff = 1000 * 60 * 60;
35
35
  return new Date(
36
- (Math.round((new Date()).getTime() / coeff) * coeff) + coeff +
37
- (1000 * 60 * offset)
36
+ Math.round(new Date().getTime() / coeff) * coeff +
37
+ coeff +
38
+ 1000 * 60 * offset
38
39
  );
39
40
  }
40
41
 
@@ -49,8 +50,10 @@ export default class DateRangeSelect extends React.Component {
49
50
  if (Object.prototype.hasOwnProperty.call(options, "date")) {
50
51
  newDate.setDate(options.date);
51
52
  }
52
- if (Object.prototype.hasOwnProperty.call(options, "time") &&
53
- options.time.match(/^[\d]{1,2}(:[\d]{1,2})?$/)) {
53
+ if (
54
+ Object.prototype.hasOwnProperty.call(options, "time") &&
55
+ options.time.match(/^[\d]{1,2}(:[\d]{1,2})?$/)
56
+ ) {
54
57
  newDate.setHours(options.time.split(":")[0]);
55
58
  newDate.setMinutes(options.time.split(":")[1] || 0);
56
59
  }
@@ -58,7 +61,9 @@ export default class DateRangeSelect extends React.Component {
58
61
  }
59
62
 
60
63
  parseDate(str) {
61
- if (!str) { return; }
64
+ if (!str) {
65
+ return;
66
+ }
62
67
  return new Date(str);
63
68
  }
64
69
 
@@ -75,40 +80,50 @@ export default class DateRangeSelect extends React.Component {
75
80
  }
76
81
 
77
82
  startsAtToString() {
78
- if (this.props.disabled) { return ""; }
83
+ if (this.props.disabled) {
84
+ return "";
85
+ }
79
86
  return this.state.startsAt.toJSON();
80
87
  }
81
88
 
82
89
  endsAtToString() {
83
- if (this.props.disabled) { return ""; }
90
+ if (this.props.disabled) {
91
+ return "";
92
+ }
84
93
  return this.state.endsAt.toJSON();
85
94
  }
86
95
 
87
96
  renderDateSelect(key, date, handleChange) {
88
97
  return (
89
98
  <div className="date-select">
90
- <select value={date.getMonth()}
91
- onChange={e => handleChange({ month: e.target.value })}
92
- disabled={this.props.disabled}>
99
+ <select
100
+ value={date.getMonth()}
101
+ onChange={(e) => handleChange({ month: e.target.value })}
102
+ disabled={this.props.disabled}>
93
103
  {this.monthOptions().map((m, i) => (
94
- <option key={key + "-month-" + i}
95
- value={i}>{m}</option>
104
+ <option key={key + "-month-" + i} value={i}>
105
+ {m}
106
+ </option>
96
107
  ))}
97
108
  </select>
98
- <select value={date.getDate()}
99
- onChange={e => handleChange({ date: e.target.value })}
100
- disabled={this.props.disabled}>
101
- {this.dayOptions().map(d => (
102
- <option key={key + "-date-" + d}
103
- value={d}>{d}</option>
109
+ <select
110
+ value={date.getDate()}
111
+ onChange={(e) => handleChange({ date: e.target.value })}
112
+ disabled={this.props.disabled}>
113
+ {this.dayOptions().map((d) => (
114
+ <option key={key + "-date-" + d} value={d}>
115
+ {d}
116
+ </option>
104
117
  ))}
105
118
  </select>
106
- <select value={date.getFullYear()}
107
- onChange={e => handleChange({ year: e.target.value })}
108
- disabled={this.props.disabled}>
109
- {this.yearOptions().map(y => (
110
- <option key={key + "-year-" + y}
111
- value={y}>{y}</option>
119
+ <select
120
+ value={date.getFullYear()}
121
+ onChange={(e) => handleChange({ year: e.target.value })}
122
+ disabled={this.props.disabled}>
123
+ {this.yearOptions().map((y) => (
124
+ <option key={key + "-year-" + y} value={y}>
125
+ {y}
126
+ </option>
112
127
  ))}
113
128
  </select>
114
129
  </div>
@@ -118,37 +133,49 @@ export default class DateRangeSelect extends React.Component {
118
133
  render() {
119
134
  return (
120
135
  <div className="date-range-select">
121
- <input type="hidden"
122
- name={this.props.objectName + "[starts_at]"}
123
- value={this.startsAtToString()} />
124
- <input type="hidden"
125
- name={this.props.objectName + "[ends_at]"}
126
- value={this.endsAtToString()} />
136
+ <input
137
+ type="hidden"
138
+ name={this.props.objectName + "[starts_at]"}
139
+ value={this.startsAtToString()}
140
+ />
141
+ <input
142
+ type="hidden"
143
+ name={this.props.objectName + "[ends_at]"}
144
+ value={this.endsAtToString()}
145
+ />
127
146
  <div className="date">
128
- {this.renderDateSelect("starts-at",
129
- this.state.startsAt,
130
- this.changeStartsAt)}
147
+ {this.renderDateSelect(
148
+ "starts-at",
149
+ this.state.startsAt,
150
+ this.changeStartsAt
151
+ )}
131
152
  {!this.props.disableTime && (
132
- <input type="text"
133
- size="5"
134
- value={this.state.startTime}
135
- disabled={this.props.disabled}
136
- onChange={e => this.setState({ startTime: e.target.value })}
137
- onBlur={e => this.changeStartsAt({ time: e.target.value })} />
153
+ <input
154
+ type="text"
155
+ size="5"
156
+ value={this.state.startTime}
157
+ disabled={this.props.disabled}
158
+ onChange={(e) => this.setState({ startTime: e.target.value })}
159
+ onBlur={(e) => this.changeStartsAt({ time: e.target.value })}
160
+ />
138
161
  )}
139
162
  </div>
140
163
  <span className="to">to</span>
141
164
  <div className="date">
142
- {this.renderDateSelect("ends-at",
143
- this.state.endsAt,
144
- this.changeEndsAt)}
165
+ {this.renderDateSelect(
166
+ "ends-at",
167
+ this.state.endsAt,
168
+ this.changeEndsAt
169
+ )}
145
170
  {!this.props.disableTime && (
146
- <input type="text"
147
- size="5"
148
- value={this.state.endTime}
149
- disabled={this.props.disabled}
150
- onChange={e => this.setState({ endTime: e.target.value })}
151
- onBlur={e => this.changeEndsAt({ time: e.target.value })} />
171
+ <input
172
+ type="text"
173
+ size="5"
174
+ value={this.state.endTime}
175
+ disabled={this.props.disabled}
176
+ onChange={(e) => this.setState({ endTime: e.target.value })}
177
+ onBlur={(e) => this.changeEndsAt({ time: e.target.value })}
178
+ />
152
179
  )}
153
180
  </div>
154
181
  </div>
@@ -162,13 +189,26 @@ export default class DateRangeSelect extends React.Component {
162
189
  // Returns an array with years from 2000 to 10 years from now.
163
190
  yearOptions() {
164
191
  let start = 2000;
165
- return Array.apply(null, Array((new Date()).getFullYear() - start + 11))
166
- .map((_, i) => i + start);
192
+ return Array.apply(null, Array(new Date().getFullYear() - start + 11)).map(
193
+ (_, i) => i + start
194
+ );
167
195
  }
168
196
 
169
197
  monthOptions() {
170
- return(["January", "February", "March", "April", "May", "June", "July",
171
- "August", "September", "October", "November", "December"]);
198
+ return [
199
+ "January",
200
+ "February",
201
+ "March",
202
+ "April",
203
+ "May",
204
+ "June",
205
+ "July",
206
+ "August",
207
+ "September",
208
+ "October",
209
+ "November",
210
+ "December"
211
+ ];
172
212
  }
173
213
 
174
214
  dayOptions() {
@@ -5,13 +5,13 @@ import useModalStore from "../stores/useModalStore";
5
5
  import { Locale, ImageResource } from "../types";
6
6
 
7
7
  interface EditableImageProps {
8
- image: ImageResource,
9
- src: string,
10
- caption: boolean,
11
- locale: string,
12
- locales: Record<string, Locale>,
13
- width: number,
14
- onUpdate?: (newImage: ImageResource, src: string) => void
8
+ image: ImageResource;
9
+ src: string;
10
+ caption: boolean;
11
+ locale: string;
12
+ locales: Record<string, Locale>;
13
+ width: number;
14
+ onUpdate?: (newImage: ImageResource, src: string) => void;
15
15
  }
16
16
 
17
17
  export default function EditableImage(props: EditableImageProps) {
@@ -43,7 +43,8 @@ export default function EditableImage(props: EditableImageProps) {
43
43
  caption={props.caption}
44
44
  locale={props.locale}
45
45
  locales={props.locales}
46
- onUpdate={updateImage} />
46
+ onUpdate={updateImage}
47
+ />
47
48
  );
48
49
  };
49
50
 
@@ -51,14 +52,17 @@ export default function EditableImage(props: EditableImageProps) {
51
52
 
52
53
  return (
53
54
  <div className="editable-image">
54
- {altWarning &&
55
- <span className="alt-warning" title="Alternative text is missing">
56
- <i className="fa-solid fa-triangle-exclamation icon" />
57
- </span>}
58
- <img src={src}
59
- width={props.width}
60
- height={height()}
61
- onClick={handleClick} />
55
+ {altWarning && (
56
+ <span className="alt-warning" title="Alternative text is missing">
57
+ <i className="fa-solid fa-triangle-exclamation icon" />
58
+ </span>
59
+ )}
60
+ <img
61
+ src={src}
62
+ width={props.width}
63
+ height={height()}
64
+ onClick={handleClick}
65
+ />
62
66
  </div>
63
67
  );
64
68
  }
@@ -1,10 +1,10 @@
1
1
  import React, { ChangeEvent, useRef } from "react";
2
2
 
3
3
  interface FileUploadButtonProps {
4
- callback: (files: File[]) => void,
5
- type: string,
6
- multiple: boolean,
7
- multiline: boolean
4
+ callback: (files: File[]) => void;
5
+ type: string;
6
+ multiple: boolean;
7
+ multiline: boolean;
8
8
  }
9
9
 
10
10
  export default function FileUploadButton(props: FileUploadButtonProps) {
@@ -32,15 +32,15 @@ export default function FileUploadButton(props: FileUploadButtonProps) {
32
32
  Drag and drop {props.type || "file"}
33
33
  {props.multiple && "s"} here, or
34
34
  {props.multiline && <br />}
35
- <button onClick={triggerDialog}>
36
- choose a file
37
- </button>
35
+ <button onClick={triggerDialog}>choose a file</button>
38
36
  </span>
39
- <input type="file"
40
- onChange={handleChange}
41
- ref={inputRef}
42
- style={{ display: "none" }}
43
- multiple={props.multiple || false} />
37
+ <input
38
+ type="file"
39
+ onChange={handleChange}
40
+ ref={inputRef}
41
+ style={{ display: "none" }}
42
+ multiple={props.multiple || false}
43
+ />
44
44
  </div>
45
45
  );
46
46
  }
@@ -1,16 +1,16 @@
1
1
  import React, { useRef, useState } from "react";
2
2
 
3
3
  interface Position {
4
- x: number,
5
- y: number,
4
+ x: number;
5
+ y: number;
6
6
  }
7
7
 
8
8
  interface FocalPointProps {
9
- x: number,
10
- y: number,
11
- onChange: (pos: Position) => void,
12
- width: number,
13
- height: number
9
+ x: number;
10
+ y: number;
11
+ onChange: (pos: Position) => void;
12
+ width: number;
13
+ height: number;
14
14
  }
15
15
 
16
16
  function clamp(val: number, min: number, max: number): number {
@@ -27,7 +27,10 @@ export default function FocalPoint(props: FocalPointProps) {
27
27
  const { width, height, onChange } = props;
28
28
 
29
29
  const [dragging, setDragging] = useState(false);
30
- const [position, setPosition] = useState<Position>({ x: props.x, y: props.y });
30
+ const [position, setPosition] = useState<Position>({
31
+ x: props.x,
32
+ y: props.y
33
+ });
31
34
 
32
35
  const containerRef = useRef<HTMLDivElement>();
33
36
  const pointRef = useRef<HTMLDivElement>();
@@ -49,7 +52,7 @@ export default function FocalPoint(props: FocalPointProps) {
49
52
 
50
53
  const drag = (evt: TouchEvent | MouseEvent) => {
51
54
  if (dragging) {
52
- let x: number , y: number;
55
+ let x: number, y: number;
53
56
  const containerSize = containerRef.current.getBoundingClientRect();
54
57
  evt.preventDefault();
55
58
 
@@ -78,17 +81,16 @@ export default function FocalPoint(props: FocalPointProps) {
78
81
  };
79
82
 
80
83
  return (
81
- <div className="focal-editor"
82
- ref={containerRef}
83
- onTouchStart={dragStart}
84
- onTouchEnd={dragEnd}
85
- onTouchMove={drag}
86
- onMouseDown={dragStart}
87
- onMouseUp={dragEnd}
88
- onMouseMove={drag}>
89
- <div className="focal-point"
90
- style={pointStyle}
91
- ref={pointRef} />
84
+ <div
85
+ className="focal-editor"
86
+ ref={containerRef}
87
+ onTouchStart={dragStart}
88
+ onTouchEnd={dragEnd}
89
+ onTouchMove={drag}
90
+ onMouseDown={dragStart}
91
+ onMouseUp={dragEnd}
92
+ onMouseMove={drag}>
93
+ <div className="focal-point" style={pointStyle} ref={pointRef} />
92
94
  </div>
93
95
  );
94
96
  }
@@ -5,12 +5,12 @@ import { cropSize, CropSize, CropState, Position, Size } from "./useCrop";
5
5
  import FocalPoint from "./FocalPoint";
6
6
 
7
7
  interface ImageProps {
8
- containerSize: Size,
9
- croppedImage: string,
10
- cropState: CropState,
11
- focalPoint: Position,
12
- setCrop: (crop: CropSize) => void,
13
- setFocal: (focal: Position) => void
8
+ containerSize: Size;
9
+ croppedImage: string;
10
+ cropState: CropState;
11
+ focalPoint: Position;
12
+ setCrop: (crop: CropSize) => void;
13
+ setFocal: (focal: Position) => void;
14
14
  }
15
15
 
16
16
  export default function Image(props: ImageProps) {
@@ -40,25 +40,29 @@ export default function Image(props: ImageProps) {
40
40
  if (props.cropState.cropping) {
41
41
  return (
42
42
  <div className="image-wrapper" style={style}>
43
- <ReactCrop src={props.cropState.image.uncropped_url}
44
- crop={cropSize(props.cropState)}
45
- minWidth={10}
46
- minHeight={10}
47
- onChange={props.setCrop} />
43
+ <ReactCrop
44
+ src={props.cropState.image.uncropped_url}
45
+ crop={cropSize(props.cropState)}
46
+ minWidth={10}
47
+ minHeight={10}
48
+ onChange={props.setCrop}
49
+ />
48
50
  </div>
49
51
  );
50
52
  } else {
51
53
  return (
52
54
  <div className="image-wrapper" style={style}>
53
55
  {props.focalPoint && (
54
- <FocalPoint width={width} height={height}
55
- x={props.focalPoint.x}
56
- y={props.focalPoint.y}
57
- onChange={props.setFocal} />
56
+ <FocalPoint
57
+ width={width}
58
+ height={height}
59
+ x={props.focalPoint.x}
60
+ y={props.focalPoint.y}
61
+ onChange={props.setFocal}
62
+ />
58
63
  )}
59
64
  <img src={props.croppedImage} />
60
65
  </div>
61
66
  );
62
67
  }
63
-
64
68
  }