mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-04 13:19:48 +03:00
publish: use CodeMirror as editor
This commit is contained in:
parent
2a0dc1a3d8
commit
30ee75413d
@ -9,7 +9,7 @@
|
||||
"@reach/menu-button": "^0.10.5",
|
||||
"@reach/tabs": "^0.10.5",
|
||||
"@tlon/indigo-light": "^1.0.3",
|
||||
"@tlon/indigo-react": "github:liam-fitzgerald/indigo-react#lf/1.2.5",
|
||||
"@tlon/indigo-react": "1.2.5",
|
||||
"aws-sdk": "^2.726.0",
|
||||
"classnames": "^2.2.6",
|
||||
"codemirror": "^5.55.0",
|
||||
|
2
pkg/interface/src/types/util.ts
Normal file
2
pkg/interface/src/types/util.ts
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
export type PropFunc<T extends (...args: any[]) => any> = Parameters<T>[0];
|
@ -0,0 +1,73 @@
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { UnControlled as CodeEditor } from "react-codemirror2";
|
||||
import { MOBILE_BROWSER_REGEX } from "~/logic/lib/util";
|
||||
import { PropFunc } from "~/types/util";
|
||||
import CodeMirror from "codemirror";
|
||||
|
||||
import "codemirror/mode/markdown/markdown";
|
||||
import "codemirror/addon/display/placeholder";
|
||||
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import { Box } from "@tlon/indigo-react";
|
||||
|
||||
const MARKDOWN_CONFIG = {
|
||||
name: "markdown",
|
||||
};
|
||||
|
||||
interface MarkdownEditorProps {
|
||||
placeholder?: string;
|
||||
value: string;
|
||||
onChange: (s: string) => void;
|
||||
onBlur?: (e: any) => void;
|
||||
}
|
||||
|
||||
export function MarkdownEditor(
|
||||
props: MarkdownEditorProps & PropFunc<typeof Box>
|
||||
) {
|
||||
const { onBlur, placeholder, value, onChange, ...boxProps } = props;
|
||||
|
||||
const options = {
|
||||
mode: MARKDOWN_CONFIG,
|
||||
theme: "tlon",
|
||||
lineNumbers: false,
|
||||
lineWrapping: true,
|
||||
scrollbarStyle: "native",
|
||||
// cursorHeight: 0.85,
|
||||
placeholder: placeholder || "",
|
||||
};
|
||||
|
||||
const handleChange = useCallback(
|
||||
(_e, _d, v: string) => {
|
||||
onChange(v);
|
||||
},
|
||||
[onChange]
|
||||
);
|
||||
|
||||
const handleBlur = useCallback(
|
||||
(_i, e: any) => {
|
||||
onBlur && onBlur(e);
|
||||
},
|
||||
[onBlur]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
flexGrow={1}
|
||||
position="static"
|
||||
className="publish"
|
||||
p={1}
|
||||
border={1}
|
||||
borderColor="lightGray"
|
||||
borderRadius={2}
|
||||
{...boxProps}
|
||||
>
|
||||
<CodeEditor
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -1,27 +1,43 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { MarkdownEditor as _MarkdownEditor, Box, ErrorMessage } from '@tlon/indigo-react';
|
||||
import { useField } from 'formik';
|
||||
import React, { useCallback } from "react";
|
||||
import _ from "lodash";
|
||||
import { Box, ErrorLabel } from "@tlon/indigo-react";
|
||||
import { useField } from "formik";
|
||||
import { MarkdownEditor } from "./MarkdownEditor";
|
||||
|
||||
const MarkdownEditor = styled(_MarkdownEditor)`
|
||||
border: 1px solid ${(p) => p.theme.colors.lightGray};
|
||||
border-radius: ${(p) => p.theme.radii[2]}px;
|
||||
`;
|
||||
export const MarkdownField = ({
|
||||
id,
|
||||
...rest
|
||||
}: { id: string } & Parameters<typeof Box>[0]) => {
|
||||
const [{ value, onBlur }, { error, touched }, { setValue }] = useField(id);
|
||||
|
||||
export const MarkdownField = ({ id, ...rest }: { id: string; } & Parameters<typeof Box>[0]) => {
|
||||
const [{ value }, { error, touched }, { setValue, setTouched }] = useField(id);
|
||||
const handleBlur = useCallback(
|
||||
(e: any) => {
|
||||
_.set(e, "target.id", id);
|
||||
console.log(e);
|
||||
onBlur && onBlur(e);
|
||||
},
|
||||
[onBlur, id]
|
||||
);
|
||||
|
||||
const hasError = !!(error && touched);
|
||||
|
||||
return (
|
||||
<Box overflowY="hidden" width="100%" display="flex" flexDirection="column" {...rest}>
|
||||
<Box
|
||||
overflowY="hidden"
|
||||
width="100%"
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
{...rest}
|
||||
>
|
||||
<MarkdownEditor
|
||||
onFocus={() => setTouched(true)}
|
||||
onBlur={() => setTouched(false)}
|
||||
borderColor={hasError ? "red" : "lightGray"}
|
||||
onBlur={handleBlur}
|
||||
value={value}
|
||||
onBeforeChange={(e, d, v) => setValue(v)}
|
||||
onChange={setValue}
|
||||
/>
|
||||
<ErrorMessage>{touched && error}</ErrorMessage>
|
||||
<ErrorLabel mt="2" hasError={!!(error && touched)}>
|
||||
{error}
|
||||
</ErrorLabel>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
@ -44,6 +44,7 @@ export function PostForm(props: PostFormProps) {
|
||||
validationSchema={formSchema}
|
||||
initialValues={initial}
|
||||
onSubmit={onSubmit}
|
||||
validateOnBlur
|
||||
>
|
||||
<Form style={{ display: "contents" }}>
|
||||
<Input width="100%" placeholder="Post Title" id="title" />
|
||||
|
@ -29,6 +29,7 @@ interface NotebookProps {
|
||||
|
||||
interface NotebookState {
|
||||
isUnsubscribing: boolean;
|
||||
tab: string;
|
||||
}
|
||||
|
||||
export class Notebook extends PureComponent<
|
||||
@ -44,7 +45,7 @@ export class Notebook extends PureComponent<
|
||||
this.setTab = this.setTab.bind(this);
|
||||
}
|
||||
|
||||
setTab(tab) {
|
||||
setTab(tab: string) {
|
||||
this.setState({ tab });
|
||||
}
|
||||
|
||||
@ -102,9 +103,7 @@ export class Notebook extends PureComponent<
|
||||
<Row justifyContent={["flex-start", "flex-end"]}>
|
||||
{isWriter && (
|
||||
<Link to={`/~publish/notebook/${ship}/${book}/new`}>
|
||||
<Button primary border>
|
||||
New Post
|
||||
</Button>
|
||||
<Button primary>New Post</Button>
|
||||
</Link>
|
||||
)}
|
||||
{!isOwn ? (
|
||||
@ -117,8 +116,7 @@ export class Notebook extends PureComponent<
|
||||
) : (
|
||||
<Button
|
||||
ml={isWriter ? 2 : 0}
|
||||
error
|
||||
border
|
||||
destructive
|
||||
onClick={() => {
|
||||
this.setState({ isUnsubscribing: true });
|
||||
api.publish
|
||||
@ -150,18 +148,22 @@ export class Notebook extends PureComponent<
|
||||
label="About"
|
||||
id="about"
|
||||
/>
|
||||
<Tab
|
||||
selected={state.tab}
|
||||
setSelected={this.setTab}
|
||||
label="Subscribers"
|
||||
id="subscribers"
|
||||
/>
|
||||
<Tab
|
||||
selected={state.tab}
|
||||
setSelected={this.setTab}
|
||||
label="Settings"
|
||||
id="settings"
|
||||
/>
|
||||
{isAdmin && (
|
||||
<>
|
||||
<Tab
|
||||
selected={state.tab}
|
||||
setSelected={this.setTab}
|
||||
label="Subscribers"
|
||||
id="subscribers"
|
||||
/>
|
||||
<Tab
|
||||
selected={state.tab}
|
||||
setSelected={this.setTab}
|
||||
label="Settings"
|
||||
id="settings"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Tabs>
|
||||
{state.tab === "all" && (
|
||||
<NotebookPosts
|
||||
@ -173,7 +175,11 @@ export class Notebook extends PureComponent<
|
||||
hideNicknames={hideNicknames}
|
||||
/>
|
||||
)}
|
||||
{state.tab === "about" && <Box color="black">{notebook?.about}</Box>}
|
||||
{state.tab === "about" && (
|
||||
<Box mt="3" color="black">
|
||||
{notebook?.about}
|
||||
</Box>
|
||||
)}
|
||||
{state.tab === "subscribers" && (
|
||||
<Subscribers
|
||||
host={ship}
|
||||
|
@ -15,7 +15,7 @@ interface NotebookPostsProps {
|
||||
|
||||
export function NotebookPosts(props: NotebookPostsProps) {
|
||||
return (
|
||||
<Col>
|
||||
<Col mt="3">
|
||||
{props.list.map((noteId: NoteId) => {
|
||||
const note = props.notes[noteId];
|
||||
if (!note) {
|
||||
|
@ -20,7 +20,7 @@ interface SettingsProps {
|
||||
}
|
||||
|
||||
const Divider = (props) => (
|
||||
<Box {...props} mb={4} borderBottom={1} borderBottomColor="lightGray" />
|
||||
<Box {...props} borderBottom={1} borderBottomColor="lightGray" />
|
||||
);
|
||||
export function Settings(props: SettingsProps) {
|
||||
const history = useHistory();
|
||||
@ -36,10 +36,11 @@ export function Settings(props: SettingsProps) {
|
||||
<Box
|
||||
mx="auto"
|
||||
maxWidth="300px"
|
||||
mb={4}
|
||||
my={4}
|
||||
gridTemplateColumns="1fr"
|
||||
gridAutoRows="auto"
|
||||
display="grid"
|
||||
gridRowGap={5}
|
||||
>
|
||||
{isUnmanaged && (
|
||||
<>
|
||||
@ -55,7 +56,7 @@ export function Settings(props: SettingsProps) {
|
||||
Permanently delete this notebook. (All current members will no longer
|
||||
see this notebook.)
|
||||
</Label>
|
||||
<Button onClick={onDelete} mt={1} border error>
|
||||
<Button mt="2" onClick={onDelete} destructive>
|
||||
Delete this notebook
|
||||
</Button>
|
||||
</Col>
|
||||
|
@ -80,7 +80,7 @@ export class Subscribers extends Component<SubscribersProps> {
|
||||
const role = roleForShip(group, window.ship)
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box mt="3">
|
||||
{ role === 'admin' && (
|
||||
<Button mb={3} border onClick={this.addAll}>
|
||||
Add all members as writers
|
||||
|
@ -65,12 +65,13 @@
|
||||
|
||||
.publish .react-codemirror2 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.publish .CodeMirror {
|
||||
padding: 12px;
|
||||
height: 100% !important;
|
||||
max-width: 700px;
|
||||
overflow-y: hidden;
|
||||
width: 100% !important;
|
||||
cursor: text;
|
||||
font-size: 12px;
|
||||
|
Loading…
Reference in New Issue
Block a user