Skip to content

Commit ac6e5b9

Browse files
committed
Break up editor correctly
1 parent 1d6e037 commit ac6e5b9

File tree

3 files changed

+155
-122
lines changed

3 files changed

+155
-122
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React, { useCallback, useEffect, useState, lazy } from 'react';
2+
import useRouter from 'use-react-router';
3+
import { ServerContext } from '@/state/server';
4+
import ace, { Editor } from 'brace';
5+
import getFileContents from '@/api/server/files/getFileContents';
6+
import styled from 'styled-components';
7+
8+
// @ts-ignore
9+
require('brace/ext/modelist');
10+
require('ayu-ace/mirage');
11+
12+
const EditorContainer = styled.div`
13+
min-height: 16rem;
14+
height: calc(100vh - 16rem);
15+
${tw`relative`};
16+
17+
#editor {
18+
${tw`rounded h-full`};
19+
}
20+
`;
21+
22+
const modes: { [k: string]: string } = {
23+
// eslint-disable-next-line @typescript-eslint/camelcase
24+
assembly_x86: 'Assembly (x86)',
25+
// eslint-disable-next-line @typescript-eslint/camelcase
26+
c_cpp: 'C++',
27+
coffee: 'Coffeescript',
28+
css: 'CSS',
29+
dockerfile: 'Dockerfile',
30+
golang: 'Go',
31+
html: 'HTML',
32+
ini: 'Ini',
33+
java: 'Java',
34+
javascript: 'Javascript',
35+
json: 'JSON',
36+
kotlin: 'Kotlin',
37+
lua: 'Luascript',
38+
perl: 'Perl',
39+
php: 'PHP',
40+
properties: 'Properties',
41+
python: 'Python',
42+
ruby: 'Ruby',
43+
// eslint-disable-next-line @typescript-eslint/camelcase
44+
plain_text: 'Plaintext',
45+
toml: 'TOML',
46+
typescript: 'Typescript',
47+
xml: 'XML',
48+
yaml: 'YAML',
49+
};
50+
51+
Object.keys(modes).forEach(mode => require(`brace/mode/${mode}`));
52+
53+
export interface Props {
54+
style?: React.CSSProperties;
55+
fetchContent: (callback: () => Promise<string>) => void;
56+
onContentSaved: (content: string) => void;
57+
}
58+
59+
export default ({ fetchContent, onContentSaved }: Props) => {
60+
const { location: { hash } } = useRouter();
61+
const [ content, setContent ] = useState('');
62+
const [ mode, setMode ] = useState('plain_text');
63+
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
64+
65+
const [ editor, setEditor ] = useState<Editor>();
66+
const ref = useCallback(node => {
67+
if (node) {
68+
setEditor(ace.edit('editor'));
69+
}
70+
}, []);
71+
72+
useEffect(() => {
73+
getFileContents(uuid, hash.replace(/^#/, ''))
74+
.then(setContent)
75+
.catch(error => console.error(error));
76+
}, [ uuid, hash ]);
77+
78+
useEffect(() => {
79+
if (!hash.length) {
80+
return;
81+
}
82+
83+
const modelist = ace.acequire('ace/ext/modelist');
84+
if (modelist) {
85+
setMode(modelist.getModeForPath(hash.replace(/^#/, '')).mode);
86+
}
87+
}, [hash]);
88+
89+
useEffect(() => {
90+
editor && editor.session.setMode(mode);
91+
}, [editor, mode]);
92+
93+
useEffect(() => {
94+
editor && editor.session.setValue(content);
95+
}, [ editor, content ]);
96+
97+
useEffect(() => {
98+
if (!editor) {
99+
fetchContent(() => Promise.reject(new Error('no editor session has been configured')));
100+
return;
101+
}
102+
103+
editor.setTheme('ace/theme/ayu-mirage');
104+
105+
editor.$blockScrolling = Infinity;
106+
editor.container.style.lineHeight = '1.375rem';
107+
editor.container.style.fontWeight = '500';
108+
editor.renderer.updateFontSize();
109+
editor.renderer.setShowPrintMargin(false);
110+
editor.session.setTabSize(4);
111+
editor.session.setUseSoftTabs(true);
112+
113+
editor.commands.addCommand({
114+
name: 'Save',
115+
bindKey: { win: 'Ctrl-s', mac: 'Command-s' },
116+
exec: (editor: Editor) => onContentSaved(editor.session.getValue()),
117+
});
118+
119+
fetchContent(() => Promise.resolve(editor.session.getValue()));
120+
}, [ editor, fetchContent, onContentSaved ]);
121+
122+
return (
123+
<EditorContainer>
124+
<div id={'editor'} ref={ref}/>
125+
<div className={'absolute pin-r pin-t z-50'}>
126+
<div className={'m-3 rounded bg-neutral-900 border border-black'}>
127+
<select
128+
className={'input-dark'}
129+
defaultValue={mode}
130+
onChange={e => setMode(`ace/mode/${e.currentTarget.value}`)}
131+
>
132+
{
133+
Object.keys(modes).map(key => (
134+
<option key={key} value={key}>{modes[key]}</option>
135+
))
136+
}
137+
</select>
138+
</div>
139+
</div>
140+
</EditorContainer>
141+
);
142+
};
Lines changed: 10 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,23 @@
1-
import React, { useCallback, useEffect, useState } from 'react';
2-
import useRouter from 'use-react-router';
1+
import React, { lazy } from 'react';
32
import { ServerContext } from '@/state/server';
4-
import getFileContents from '@/api/server/files/getFileContents';
5-
import ace, { Editor } from 'brace';
6-
import styled from 'styled-components';
73

8-
// @ts-ignore
9-
require('brace/ext/modelist');
10-
require('ayu-ace/mirage');
11-
12-
const EditorContainer = styled.div`
13-
min-height: 16rem;
14-
height: calc(100vh - 16rem);
15-
${tw`relative`};
16-
17-
#editor {
18-
${tw`rounded h-full`};
19-
}
20-
`;
21-
22-
const modes: { [k: string]: string } = {
23-
// eslint-disable-next-line @typescript-eslint/camelcase
24-
assembly_x86: 'Assembly (x86)',
25-
// eslint-disable-next-line @typescript-eslint/camelcase
26-
c_cpp: 'C++',
27-
coffee: 'Coffeescript',
28-
css: 'CSS',
29-
dockerfile: 'Dockerfile',
30-
golang: 'Go',
31-
html: 'HTML',
32-
ini: 'Ini',
33-
java: 'Java',
34-
javascript: 'Javascript',
35-
json: 'JSON',
36-
kotlin: 'Kotlin',
37-
lua: 'Luascript',
38-
perl: 'Perl',
39-
php: 'PHP',
40-
properties: 'Properties',
41-
python: 'Python',
42-
ruby: 'Ruby',
43-
// eslint-disable-next-line @typescript-eslint/camelcase
44-
plain_text: 'Plaintext',
45-
toml: 'TOML',
46-
typescript: 'Typescript',
47-
xml: 'XML',
48-
yaml: 'YAML',
49-
};
50-
51-
Object.keys(modes).forEach(mode => require(`brace/mode/${mode}`));
4+
const LazyAceEditor = lazy(() => import(/* webpackChunkName: "editor" */'@/components/elements/AceEditor'));
525

536
export default () => {
54-
const { location: { hash } } = useRouter();
55-
const [ content, setContent ] = useState('');
56-
const [ mode, setMode ] = useState('plain_text');
577
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
588

59-
const [ editor, setEditor ] = useState<Editor>();
60-
const ref = useCallback(node => {
61-
if (node) {
62-
setEditor(ace.edit('editor'));
63-
}
64-
}, []);
65-
66-
useEffect(() => {
67-
getFileContents(uuid, hash.replace(/^#/, ''))
68-
.then(setContent)
69-
.catch(error => console.error(error));
70-
}, [ uuid, hash ]);
71-
72-
useEffect(() => {
73-
if (!hash.length) {
74-
return;
75-
}
76-
77-
const modelist = ace.acequire('ace/ext/modelist');
78-
if (modelist) {
79-
setMode(modelist.getModeForPath(hash.replace(/^#/, '')).mode);
80-
}
81-
}, [hash]);
82-
83-
useEffect(() => {
84-
editor && editor.session.setMode(mode);
85-
}, [editor, mode]);
86-
87-
useEffect(() => {
88-
editor && editor.session.setValue(content);
89-
}, [ editor, content ]);
90-
91-
useEffect(() => {
92-
if (!editor) {
93-
return;
94-
}
95-
96-
editor.setTheme('ace/theme/ayu-mirage');
9+
let ref: null| (() => Promise<string>) = null;
9710

98-
editor.$blockScrolling = Infinity;
99-
editor.container.style.lineHeight = '1.375rem';
100-
editor.container.style.fontWeight = '500';
101-
editor.renderer.updateFontSize();
102-
editor.renderer.setShowPrintMargin(false);
103-
editor.session.setTabSize(4);
104-
editor.session.setUseSoftTabs(true);
105-
}, [ editor ]);
11+
setTimeout(() => ref && ref().then(console.log), 5000);
10612

10713
return (
10814
<div className={'my-10'}>
109-
<EditorContainer>
110-
<div id={'editor'} ref={ref}/>
111-
<div className={'absolute pin-r pin-t z-50'}>
112-
<div className={'m-3 rounded bg-neutral-900 border border-black'}>
113-
<select
114-
className={'input-dark'}
115-
defaultValue={mode}
116-
onChange={e => setMode(`ace/mode/${e.currentTarget.value}`)}
117-
>
118-
{
119-
Object.keys(modes).map(key => (
120-
<option key={key} value={key}>{modes[key]}</option>
121-
))
122-
}
123-
</select>
124-
</div>
125-
</div>
126-
</EditorContainer>
15+
<LazyAceEditor
16+
fetchContent={value => {
17+
ref = value;
18+
}}
19+
onContentSaved={() => null}
20+
/>
12721
</div>
12822
);
12923
};

resources/scripts/routers/ServerRouter.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import DatabasesContainer from '@/components/server/databases/DatabasesContainer
1111
import FileManagerContainer from '@/components/server/files/FileManagerContainer';
1212
import { CSSTransition } from 'react-transition-group';
1313
import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
14-
15-
const LazyFileEditContainer = lazy<React.ComponentType<RouteComponentProps<any>>>(
16-
() => import(/* webpackChunkName: "editor" */'@/components/server/files/FileEditContainer')
17-
);
14+
import FileEditContainer from '@/components/server/files/FileEditContainer';
1815

1916
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
2017
const server = ServerContext.useStoreState(state => state.server.data);
@@ -25,7 +22,7 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
2522
getServer(match.params.id);
2623
}
2724

28-
useEffect(() => () => clearServerState(), []);
25+
useEffect(() => () => clearServerState(), [ clearServerState ]);
2926

3027
return (
3128
<React.Fragment>
@@ -59,7 +56,7 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
5956
path={`${match.path}/files/edit`}
6057
render={props => (
6158
<SuspenseSpinner>
62-
<LazyFileEditContainer {...props}/>
59+
<FileEditContainer {...props as any}/>
6360
</SuspenseSpinner>
6461
)}
6562
exact

0 commit comments

Comments
 (0)