mirror of
https://github.com/muerwre/markdown-home-tab.git
synced 2025-04-25 00:46:41 +07:00
add hotkeys
This commit is contained in:
parent
6d00bffbec
commit
db911e51e4
14 changed files with 91 additions and 73 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -23,3 +23,5 @@ dist-ssr
|
|||
*.sln
|
||||
*.sw?
|
||||
web-ext-artifacts
|
||||
output
|
||||
*.tgz
|
|
@ -22,4 +22,4 @@ yarn dev
|
|||
|
||||
## TO-DO
|
||||
|
||||
- Use Remirror as editor
|
||||
- Use HyperMD editor
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "markdown-home-tab",
|
||||
"private": true,
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"package": "yarn build && web-ext build -s ./dist",
|
||||
"package": "yarn build && web-ext build -s ./dist -a ./output",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Markdown Home Tab",
|
||||
"short_name": "Markdown New Tab",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"description": "Markdown right in your home tab! Paste links, pictures, lists and more. You can also customize colors to match your needs.",
|
||||
"manifest_version": 2,
|
||||
"permissions": ["storage"],
|
||||
|
|
|
@ -13,7 +13,7 @@ const EmptyViewer: FC<EmptyViewerProps> = ({ startEditing }) => {
|
|||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className={styles.empty} style={style}>
|
||||
<div className={styles.empty} style={style} onDoubleClick={startEditing}>
|
||||
<div className={styles.title}>{t(`Nothing's here yet`)}</div>
|
||||
<div>
|
||||
<Button
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
box-sizing: border-box;
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.5;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FC } from "react";
|
||||
import { FC, useCallback, MouseEvent } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { useContainerPaddings } from "~/modules/theme/hooks/useContainerPaddings";
|
||||
import styles from "./styles.module.scss";
|
||||
|
@ -7,20 +7,26 @@ import { useTranslation } from "react-i18next";
|
|||
import remarkGfm from "remark-gfm";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
|
||||
interface ReactMarkdownViewerProps {
|
||||
interface Props {
|
||||
value: string;
|
||||
startEditing: () => void;
|
||||
}
|
||||
|
||||
const ReactMarkdownViewer: FC<ReactMarkdownViewerProps> = ({
|
||||
value,
|
||||
startEditing,
|
||||
}) => {
|
||||
const MarkdownViewer: FC<Props> = ({ value, startEditing }) => {
|
||||
const { t } = useTranslation();
|
||||
const style = useContainerPaddings();
|
||||
|
||||
const onDoubleClick = useCallback(
|
||||
(event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
startEditing();
|
||||
},
|
||||
[startEditing]
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={style} className={styles.editor}>
|
||||
<div style={style} className={styles.editor} onDoubleClick={onDoubleClick}>
|
||||
<div className={styles.edit}>
|
||||
<Button
|
||||
size="small"
|
||||
|
@ -41,4 +47,4 @@ const ReactMarkdownViewer: FC<ReactMarkdownViewerProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export { ReactMarkdownViewer };
|
||||
export { MarkdownViewer };
|
|
@ -1,37 +1,16 @@
|
|||
import { FC, useCallback } from "react";
|
||||
|
||||
import {
|
||||
EditorComponent,
|
||||
FloatingToolbar,
|
||||
FormattingButtonGroup,
|
||||
HeadingLevelButtonGroup,
|
||||
Remirror,
|
||||
useRemirror,
|
||||
EditorComponent,
|
||||
HeadingLevelButtonGroup,
|
||||
FormattingButtonGroup,
|
||||
} from "@remirror/react";
|
||||
import jsx from "refractor/lang/jsx.js";
|
||||
import typescript from "refractor/lang/typescript.js";
|
||||
import { Extension, ExtensionPriority, RemirrorEventListener } from "remirror";
|
||||
import {
|
||||
BlockquoteExtension,
|
||||
UnderlineExtension,
|
||||
BoldExtension,
|
||||
BulletListExtension,
|
||||
CodeBlockExtension,
|
||||
CodeExtension,
|
||||
HardBreakExtension,
|
||||
HeadingExtension,
|
||||
ItalicExtension,
|
||||
LinkExtension,
|
||||
ListItemExtension,
|
||||
MarkdownExtension,
|
||||
OrderedListExtension,
|
||||
StrikeExtension,
|
||||
TableExtension,
|
||||
TrailingNodeExtension,
|
||||
GapCursorExtension,
|
||||
} from "remirror/extensions";
|
||||
import styles from "./styles.module.scss";
|
||||
import { Extension, RemirrorEventListener } from "remirror";
|
||||
import { useContainerPaddings } from "~/modules/theme/hooks/useContainerPaddings";
|
||||
import styles from "./styles.module.scss";
|
||||
|
||||
interface RemirrorEditorProps {
|
||||
locked: boolean;
|
||||
|
@ -50,7 +29,7 @@ const RemirrorEditor: FC<RemirrorEditorProps> = ({
|
|||
exitMarksOnArrowPress: false,
|
||||
},
|
||||
content: value,
|
||||
stringHandler: "markdown",
|
||||
// stringHandler: "markdown",
|
||||
});
|
||||
|
||||
const onStateChange = useCallback<RemirrorEventListener<Extension>>(
|
||||
|
@ -90,26 +69,26 @@ const RemirrorEditor: FC<RemirrorEditorProps> = ({
|
|||
};
|
||||
|
||||
const extensions = (): Extension[] => [
|
||||
new LinkExtension({ autoLink: true }),
|
||||
new BoldExtension(),
|
||||
new UnderlineExtension(),
|
||||
new StrikeExtension(),
|
||||
new ItalicExtension(),
|
||||
new HeadingExtension(),
|
||||
new BlockquoteExtension(),
|
||||
new BulletListExtension({ enableSpine: false }),
|
||||
new OrderedListExtension(),
|
||||
new ListItemExtension({
|
||||
priority: ExtensionPriority.High,
|
||||
// enableCollapsible: true,
|
||||
}),
|
||||
new CodeExtension(),
|
||||
new CodeBlockExtension({ supportedLanguages: [jsx, typescript] }),
|
||||
new TrailingNodeExtension(),
|
||||
new TableExtension(),
|
||||
new MarkdownExtension({ copyAsMarkdown: true }),
|
||||
new GapCursorExtension(),
|
||||
new HardBreakExtension(),
|
||||
// new LinkExtension({ autoLink: true }),
|
||||
// new BoldExtension(),
|
||||
// new UnderlineExtension(),
|
||||
// new StrikeExtension(),
|
||||
// new ItalicExtension(),
|
||||
// new HeadingExtension(),
|
||||
// new BlockquoteExtension(),
|
||||
// new BulletListExtension({ enableSpine: false }),
|
||||
// new OrderedListExtension(),
|
||||
// new ListItemExtension({
|
||||
// priority: ExtensionPriority.High,
|
||||
// // enableCollapsible: true,
|
||||
// }),
|
||||
// new CodeExtension(),
|
||||
// new CodeBlockExtension({ supportedLanguages: [jsx, typescript] }),
|
||||
// new TrailingNodeExtension(),
|
||||
// new TableExtension(),
|
||||
// new MarkdownExtension({ copyAsMarkdown: true }),
|
||||
// new GapCursorExtension(),
|
||||
// new HardBreakExtension(),
|
||||
];
|
||||
|
||||
export { RemirrorEditor };
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { ChangeEvent, FC, useCallback, useMemo } from "react";
|
||||
import { ChangeEvent, FC, useCallback, useMemo, KeyboardEvent } from "react";
|
||||
import styles from "./styles.module.scss";
|
||||
import { useTheme } from "~/modules/theme/context/ThemeContext";
|
||||
|
||||
interface ReactMarkdownEditorProps {
|
||||
value: string;
|
||||
onChange: (val: string) => void;
|
||||
save: VoidFunction;
|
||||
}
|
||||
|
||||
const ReactMarkdownEditor: FC<ReactMarkdownEditorProps> = ({
|
||||
const SimpleTextareaEditor: FC<ReactMarkdownEditorProps> = ({
|
||||
save,
|
||||
value,
|
||||
onChange,
|
||||
}) => {
|
||||
|
@ -27,8 +29,22 @@ const ReactMarkdownEditor: FC<ReactMarkdownEditorProps> = ({
|
|||
[paddingHorizontal, paddingVertical]
|
||||
);
|
||||
|
||||
const onKeyDown = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.key === "Enter" && event.ctrlKey) {
|
||||
save();
|
||||
}
|
||||
|
||||
if (event.key === "Escape") {
|
||||
save();
|
||||
}
|
||||
},
|
||||
[save]
|
||||
);
|
||||
|
||||
return (
|
||||
<textarea
|
||||
onKeyDown={onKeyDown}
|
||||
onChange={changeHandler}
|
||||
className={styles.textarea}
|
||||
style={style}
|
||||
|
@ -39,4 +55,4 @@ const ReactMarkdownEditor: FC<ReactMarkdownEditorProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export { ReactMarkdownEditor };
|
||||
export { SimpleTextareaEditor };
|
|
@ -1,6 +1,6 @@
|
|||
import { FC, Suspense, lazy } from "react";
|
||||
import { ReactMarkdownEditor } from "../../components/ReactMarkdownEditor";
|
||||
import { ReactMarkdownViewer } from "../../components/ReactMarkdownViewer";
|
||||
import { SimpleTextareaEditor } from "../../components/SimpleTextareaEditor";
|
||||
import { MarkdownViewer } from "../../components/MarkdownViewer";
|
||||
import { usePersistedValue } from "./hooks/usePersistedValue";
|
||||
import styles from "./styles.module.scss";
|
||||
import { useSettings } from "~/modules/settings/context/SettingsContext";
|
||||
|
@ -10,8 +10,8 @@ import { EditorWrapper } from "../../components/EditorWrapper";
|
|||
interface MarkdownEditorContainerProps {
|
||||
id: string;
|
||||
locked: boolean;
|
||||
startEditing: () => void;
|
||||
remove: () => void;
|
||||
startEditing: VoidCallback;
|
||||
remove: VoidCallback;
|
||||
}
|
||||
|
||||
const RichEditor = lazy(() =>
|
||||
|
@ -40,7 +40,7 @@ export const MarkdownEditorContainer: FC<MarkdownEditorContainerProps> = ({
|
|||
const viewer = empty ? (
|
||||
<EmptyViewer startEditing={startEditing} />
|
||||
) : (
|
||||
<ReactMarkdownViewer value={value} startEditing={startEditing} />
|
||||
<MarkdownViewer value={value} startEditing={startEditing} />
|
||||
);
|
||||
|
||||
const editor = (
|
||||
|
@ -48,13 +48,17 @@ export const MarkdownEditorContainer: FC<MarkdownEditorContainerProps> = ({
|
|||
{richEditorEnabled ? (
|
||||
<RichEditor value={value} onChange={setValue} locked={locked} />
|
||||
) : (
|
||||
<ReactMarkdownEditor value={value} onChange={setValue} />
|
||||
<SimpleTextareaEditor
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
save={startEditing}
|
||||
/>
|
||||
)}
|
||||
</EditorWrapper>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.editor}>
|
||||
<div className={styles.editor} id={id}>
|
||||
{hydrated && <Suspense>{locked ? viewer : editor}</Suspense>}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -44,6 +44,15 @@ const DefaultLayout = ({
|
|||
...panelProps.params,
|
||||
locked: !locked,
|
||||
});
|
||||
|
||||
if (panelProps.params.locked) {
|
||||
setTimeout(() => {
|
||||
document
|
||||
.getElementById(panelProps.api.id)
|
||||
?.querySelector("textarea")
|
||||
?.focus();
|
||||
}, 0);
|
||||
}
|
||||
}, [locked, panelProps.api, panelProps.params]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||
import { RowGroup } from "~/components/containers/RowGroup";
|
||||
import { SettingsRow } from "~/components/containers/SettingsRow";
|
||||
import {
|
||||
ColorSettings,
|
||||
ColorSettings as ColorSettingsValue,
|
||||
SettingsValue,
|
||||
useSettings,
|
||||
} from "~/modules/settings/context/SettingsContext";
|
||||
|
@ -37,7 +37,7 @@ const ColorSettings: FC = () => {
|
|||
);
|
||||
|
||||
const setThemeColors = useCallback(
|
||||
(val: ColorSettings) => {
|
||||
(val: ColorSettingsValue) => {
|
||||
update(fillThemeHeadings(val));
|
||||
},
|
||||
[update]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue