Skip to content

Commit

Permalink
add plate editing library (#78)
Browse files Browse the repository at this point in the history
- add @udecode/plate library and migrate various custom slate code to it (closes #68 )
- add toolbar and various wysiwyg shortcuts
- add  fancy code blocks
- add list support (through shortcuts only)
- remove markdown support
- add a test for the parse step, even though i cannot get it to run :|
- add a top-level ErrorBoundary
- update remark related dependencies
- organize and refactor remark usage post upgrade #49 
- clean-out a few other unused dependencies #38 
- move rebuild from postinstall to specific command (avoids rebuilding every dependency change)
  • Loading branch information
cloverich authored Oct 15, 2021
1 parent 3edac46 commit 4c8d54d
Show file tree
Hide file tree
Showing 37 changed files with 4,381 additions and 1,503 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,3 @@ tmp/
# build output
dist/
packaged/

# Generated prisma client
# Configured in schema.prisma
prisma/
4 changes: 3 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ cp package.json dist/
cp yarn.lock dist/

# see package.js
# Could embed here but it is already setup as a postinstall script
cp ./rebuild-better-sqlite3.sh dist/

# todo: This is installing dev dependencies which, because of webpack, should not be needed.
# When I use install --production, the final build complains it cannot find electron. Sigh.
cd dist/
yarn
# todo: this only handles sqlite3... electron-rebuild (once fixed) would address all
# modules w/ native dependencies
yarn rebuild

cd ../

Expand Down
43 changes: 22 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,23 @@
"start": "yarn dev:webpack & yarn dev:electron",
"dev:webpack": "webpack-dev-server --config webpack.js --hot --inline --colors",
"dev:electron": "electron src/electron/index.js",
"test": "mocha -r ts-node/register -r esm src/**/*.test.ts",
"test": "mocha -r esm -r ts-node/register src/**/*.test.ts",
"test:one": "mocha -r ts-node/register -r esm",
"postinstall": "./rebuild-better-sqlite3.sh"
"rebuild": "./rebuild-better-sqlite3.sh"
},
"dependencies": {
"ajv": "^8.6.2",
"ajv-formats": "^2.1.0",
"better-sqlite3": "^7.4.3",
"cuid": "^2.1.8",
"electron-store": "^8.0.1",
"get-port": "^5.1.1",
"klaw": "^3.0.0",
"ky": "^0.20.0",
"ky-universal": "^0.8.1",
"ky": "^0.28.6",
"ky-universal": "^0.9.1",
"lodash": "^4.17.20",
"luxon": "^1.24.1",
"mime": "^2.5.2",
"mkdirp": "^1.0.4",
"remark": "^12.0.0",
"remark-gfm": "^2.0.0",
"remark-parse": "^8.0.3",
"remark-stringify": "^8.1.1",
"ts-mdast": "^1.0.0",
"unified": "^9.1.0"
"mkdirp": "^1.0.4"
},
"devDependencies": {
"@types/better-sqlite3": "^5.4.0",
Expand All @@ -39,10 +32,10 @@
"@types/luxon": "^1.24.3",
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^7.0.2",
"@types/prismjs": "^1.16.1",
"@types/react": "^17.0.27",
"@types/react-dom": "^17.0.9",
"@types/rehype-react": "^4.0.0",
"@udecode/plate": "^5.3.0",
"chai": "^4.2.0",
"chai-json-schema-ajv": "^5.2.4",
"css-loader": "^3.6.0",
Expand All @@ -56,23 +49,31 @@
"html-webpack-plugin": "^4.3.0",
"mobx": "^5.15.4",
"mobx-react-lite": "^2.0.7",
"mocha": "^8.0.1",
"prismjs": "^1.21.0",
"mocha": "^9.1.3",
"react": "^17.0.2",
"react-day-picker": "^7.4.10",
"react-dom": "^17.0.2",
"rehype-react": "^6.1.0",
"remark-rehype": "^7.0.0",
"rehype-react": "^7.0.3",
"remark": "^14.0.1",
"remark-gfm": "^3.0.0",
"remark-parse": "^8.0.3",
"remark-rehype": "^10.0.0",
"remark-slate-transformer": "^0.4.1",
"slate": "^0.65.3",
"slate-history": "^0.65.3",
"slate-react": "^0.65.3",
"remark-stringify": "^8.1.1",
"remark-unwrap-images": "^3.0.0",
"slate": "^0.66.5",
"slate-history": "^0.66.0",
"slate-hyperscript": "^0.66.0",
"slate-react": "^0.66.7",
"source-map-loader": "^1.0.0",
"spectre.css": "^0.5.8",
"style-loader": "^1.2.1",
"styled-components": "^5.3.1",
"ts-loader": "^7.0.5",
"ts-node": "^8.10.2",
"ts-mdast": "^1.0.0",
"ts-node": "^10.3.0",
"typescript": "^4.3.5",
"unified": "^10.1.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
Expand Down
1 change: 0 additions & 1 deletion src/electron/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ let dbfile = settings.get(DATABASE_URL);
function setDatabaseUrl(url) {
if (!url) throw new Error('setDatabaseUrl called with null or empty string');

// todo: validate it can be loaded (or created) by Prisma client
settings.set(DATABASE_URL, url);
}

Expand Down
62 changes: 62 additions & 0 deletions src/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from "react";
import { Pane, Alert } from "evergreen-ui";

interface State {
hasError: boolean;
error: any;
}

export default class ErrorBoundary extends React.Component<any, State> {
constructor(props: any) {
super(props);
this.state = { hasError: false, error: null };
}

static getDerivedStateFromError(error: any) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error };
}

componentDidCatch(error: any, errorInfo: any) {
// You can also log the error to an error reporting service
console.error("top level error boundary reached:", error, errorInfo);
}

renderError() {
let errStr: string = "Unable to parse error for display. Check console? :|";
let stack: string = "";
try {
if (this.state.error instanceof Error) {
errStr = this.state.error.message;
stack = this.state.error.stack || "";
} else if (typeof this.state.error === "string") {
errStr = this.state.error;
} else {
errStr = JSON.stringify(this.state.error, null, 2);
}
errStr = JSON.stringify(this.state.error, null, 2);
} catch (err) {
console.error(
"Error parsing error to string in top-level Error boundary"
);
}

return (
<Pane padding={50}>
<Alert intent="danger" title="Unhandled Error" overflow="auto">
<p>There was an unhandled error that crashed the app</p>
<pre>{errStr}</pre>
<pre>{stack}</pre>
</Alert>
</Pane>
);
}

render() {
if (this.state.hasError) {
return this.renderError();
}

return this.props.children;
}
}
4 changes: 2 additions & 2 deletions src/hooks/loadutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useState, useCallback } from "react";
import { toaster } from "evergreen-ui";

// For errror handling. Also doesn't really need to be here
import ky from "ky-universal";
import ky, { HTTPError } from "ky-universal";

// https://stackoverflow.com/questions/53215285/how-can-i-force-component-to-re-render-with-hooks-in-react
function useForceUpdate() {
Expand Down Expand Up @@ -106,7 +106,7 @@ export function withLoading<T extends any[], U>(
// Extract the API error message, if any.
// todo: A convention for error structure (like title/details)
// would probably support moving this logic into the client library
if (err instanceof ky.HTTPError) {
if (err instanceof HTTPError) {
try {
// Basically if the error comes from my backend, pull out the
// error title then propagate. Client library should handle this.
Expand Down
52 changes: 28 additions & 24 deletions src/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { PropsWithChildren } from "react";
import { Pane, Tablist, Tab } from "evergreen-ui";
import ErrorBoundary from "./error";

type View = 'journals' | 'documents' | 'preferences';
type View = "journals" | "documents" | "preferences";

interface Props {
selected?: View;
Expand All @@ -13,33 +14,36 @@ const monoStyle = {
};

export default function Layout(props: PropsWithChildren<Props>) {

// todo: optimize
const tabs = (['journals', 'documents', 'preferences'] as View[]).map((tab) => {
return (
<Tab
key={tab as any}
onSelect={() => props.setSelected(tab)}
isSelected={props.selected === tab}
aria-controls={`panel-${tab}`}
>
{tab}
</Tab>
);
});
const tabs = (["journals", "documents", "preferences"] as View[]).map(
(tab) => {
return (
<Tab
key={tab as any}
onSelect={() => props.setSelected(tab)}
isSelected={props.selected === tab}
aria-controls={`panel-${tab}`}
>
{tab}
</Tab>
);
}
);

return (
<Pane>
<Pane borderBottom="default" elevation={1} padding={15} display="flex">
<Pane marginRight={25}>
<span style={monoStyle}>#</span>
<span style={monoStyle}>chronicles</span>
<ErrorBoundary>
<Pane>
<Pane borderBottom="default" elevation={1} padding={15} display="flex">
<Pane marginRight={25}>
<span style={monoStyle}>#</span>
<span style={monoStyle}>chronicles</span>
</Pane>
<Tablist flexGrow={1} marginRight={24}>
{tabs}
</Tablist>
</Pane>
<Tablist flexGrow={1} marginRight={24}>
{tabs}
</Tablist>
<Pane margin={50}>{props.children}</Pane>
</Pane>
<Pane margin={50}>{props.children}</Pane>
</Pane>
</ErrorBoundary>
);
}
100 changes: 0 additions & 100 deletions src/markdown.ts

This file was deleted.

Loading

0 comments on commit 4c8d54d

Please sign in to comment.