Skip to content

Commit 2342777

Browse files
committed
WiP on adding minimal editor after frontend file upload
1 parent 72fb5fc commit 2342777

File tree

4 files changed

+85
-5
lines changed

4 files changed

+85
-5
lines changed

client/browser/BrowserEditor.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, {lazy, Suspense, useMemo} from 'react';
2+
import SelectLabels from '../finder/SelectLabels';
3+
4+
5+
export default function BrowserEditor(props) {
6+
const {uploadedFile, mainContent} = props;
7+
const DetailEditor = useMemo(() => {
8+
if (uploadedFile.file_info.browser_component) {
9+
const component = `./components/browser/${uploadedFile.file_info.browser_component}.js`;
10+
const LazyItem = lazy(() => import(component));
11+
return (props) => (
12+
<div className="detail-editor">
13+
<Suspense fallback={<span>{gettext("Loading...")}</span>}>
14+
<LazyItem fileInfo={props.file_info} />
15+
</Suspense>
16+
<form>
17+
<SelectLabels settings={{labels: uploadedFile.labels, mainContent: mainContent}} />
18+
<div dangerouslySetInnerHTML={{__html: props.form_html}} />
19+
</form>
20+
</div>
21+
);
22+
}
23+
return (props) => (
24+
<div className="detail-editor">
25+
<img src={props.file_info.thumbnail_url} />
26+
<form>
27+
<SelectLabels settings={{labels: uploadedFile.labels, mainContent: mainContent}} />
28+
<div dangerouslySetInnerHTML={{__html: props.form_html}} />
29+
</form>
30+
</div>
31+
);
32+
}, [uploadedFile.file_info.browser_component]);
33+
34+
return <DetailEditor {...uploadedFile} />;
35+
}

client/browser/FileSelectDialog.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import React, {
99
} from 'react';
1010
import {Tooltip} from 'react-tooltip';
1111
import FigureLabels from '../finder/FigureLabels';
12+
import BrowserEditor from './BrowserEditor';
1213
import FileUploader from '../finder/FileUploader';
1314
import FolderStructure from './FolderStructure';
1415
import Menu from './Menu';
@@ -68,6 +69,8 @@ const FilesList = memo((props: any) => {
6869
export default function FileSelectDialog(props) {
6970
const {baseUrl, csrfToken, realm, selectFile} = props;
7071
const [structure, setStructure] = useState({root_folder: null, last_folder: null, files: null});
72+
const [uploadedFile, setUploadedFile] = useState(null);
73+
const ref = useRef(null);
7174
const uploaderRef = useRef(null);
7275

7376
useEffect(() => {
@@ -107,13 +110,12 @@ export default function FileSelectDialog(props) {
107110
setStructure({...structure});
108111
}
109112

110-
function handleUpload(folderId, files) {
111-
fetchFiles(folderId);
112-
selectFile(files[0]);
113+
function handleUpload(folderId, uploadedFiles) {
114+
setUploadedFile(uploadedFiles[0]);
113115
}
114116

115117
return structure.root_folder && (<>
116-
<div className="wrapper">
118+
<div className="wrapper" ref={ref}>
117119
<Menu
118120
lastFolderId={structure.last_folder}
119121
fetchFiles={fetchFiles}
@@ -131,6 +133,8 @@ export default function FileSelectDialog(props) {
131133
/>
132134
</ul>
133135
</nav>
136+
{uploadedFile ?
137+
<BrowserEditor uploadedFile={uploadedFile} mainContent={ref.current} /> :
134138
<FileUploader
135139
folderId={structure.last_folder}
136140
handleUpload={handleUpload}
@@ -140,7 +144,7 @@ export default function FileSelectDialog(props) {
140144
structure.files === null ?
141145
<div className="status">{gettext("Loading files…")}</div> :
142146
<FilesList files={structure.files} selectFile={selectFile} />
143-
}</FileUploader>
147+
}</FileUploader>}
144148
</div>
145149
</div>
146150
<Tooltip id="django-finder-tooltip" place="bottom-start" />
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React, {useRef, useState} from 'react';
2+
import ReactCrop, {Crop} from 'react-image-crop';
3+
4+
5+
export default function Image(props) {
6+
const {fileInfo} = props;
7+
const ref = useRef(null);
8+
const [crop, setCrop] = useState<Crop>(null);
9+
10+
function handleChange(crop) {
11+
const shadowRoot = ref.current?.getRootNode();
12+
if (!shadowRoot)
13+
return;
14+
const cropFields = {
15+
x: shadowRoot.getElementById('id_crop_x') as HTMLInputElement,
16+
y: shadowRoot.getElementById('id_crop_y') as HTMLInputElement,
17+
size: shadowRoot.getElementById('id_crop_size') as HTMLInputElement,
18+
width: shadowRoot.getElementById('id_width') as HTMLInputElement,
19+
height: shadowRoot.getElementById('id_height') as HTMLInputElement,
20+
};
21+
22+
setCrop(crop);
23+
if (crop) {
24+
const rect = ref.current.getBoundingClientRect();
25+
cropFields.x.value = String(crop.x / rect.width * parseInt(cropFields.width.value));
26+
cropFields.y.value = String(crop.y / rect.height * parseInt(cropFields.height.value));
27+
cropFields.size.value = String(crop.width / rect.width * parseInt(cropFields.width.value));
28+
} else {
29+
cropFields.x.value = '';
30+
cropFields.y.value = '';
31+
cropFields.size.value = '';
32+
}
33+
}
34+
35+
return (
36+
<ReactCrop crop={crop} aspect={1} onChange={handleChange}>
37+
<img className="editable" src={fileInfo.download_url} ref={ref} />
38+
</ReactCrop>
39+
);
40+
}

client/esbuild.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ await build({
1111
'client/finder-select.ts',
1212
'client/folder-admin.tsx',
1313
'client/file-admin.tsx',
14+
'client/components/browser/*.tsx',
1415
'client/components/editor/*.tsx',
1516
'client/components/folderitem/*.tsx',
1617
'client/components/menuextension/*.tsx',

0 commit comments

Comments
 (0)