Flexible LHS and RHS with flex
parent
a7cd3ea7e0
commit
1b0048cdcf
|
@ -32,14 +32,22 @@ export function flashNotification(message: string): Promise<void> {
|
||||||
return syscall("editor.flashNotification", message);
|
return syscall("editor.flashNotification", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showRhs(html: string): Promise<void> {
|
export function showRhs(html: string, flex = 1): Promise<void> {
|
||||||
return syscall("editor.showRhs", html);
|
return syscall("editor.showRhs", html, flex);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hideRhs(): Promise<void> {
|
export function hideRhs(): Promise<void> {
|
||||||
return syscall("editor.hideRhs");
|
return syscall("editor.hideRhs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function showLhs(html: string, flex = 1): Promise<void> {
|
||||||
|
return syscall("editor.showLhs", html, flex);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideLhs(): Promise<void> {
|
||||||
|
return syscall("editor.hideLhs");
|
||||||
|
}
|
||||||
|
|
||||||
export function insertAtPos(text: string, pos: number): Promise<void> {
|
export function insertAtPos(text: string, pos: number): Promise<void> {
|
||||||
return syscall("editor.insertAtPos", text, pos);
|
return syscall("editor.insertAtPos", text, pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ functions:
|
||||||
path: "./markdown.ts:togglePreview"
|
path: "./markdown.ts:togglePreview"
|
||||||
command:
|
command:
|
||||||
name: "Toggle Markdown Preview"
|
name: "Toggle Markdown Preview"
|
||||||
|
key: Ctrl-p
|
||||||
|
mac: Cmd-p
|
||||||
preview:
|
preview:
|
||||||
path: "./markdown.ts:updateMarkdownPreview"
|
path: "./markdown.ts:updateMarkdownPreview"
|
||||||
env: client
|
env: client
|
||||||
|
|
|
@ -48,7 +48,7 @@ export async function updateMarkdownPreview() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let html = md.render(renderMarkdown(mdTree));
|
let html = md.render(renderMarkdown(mdTree));
|
||||||
await showRhs(`<html><body>${html}</body></html>`);
|
await showRhs(`<html><body>${html}</body></html>`, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hideMarkdownPreview() {
|
async function hideMarkdownPreview() {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import {useEffect, useRef} from "react";
|
import {useEffect, useRef} from "react";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import iframeHtml from "bundle-text:./panel.html";
|
import iframeHtml from "bundle-text:./panel.html";
|
||||||
import {Simulate} from "react-dom/test-utils";
|
|
||||||
|
|
||||||
export function Panel({ html }: { html: string }) {
|
export function Panel({ html, flex }: { html: string; flex: number }) {
|
||||||
const iFrameRef = useRef<HTMLIFrameElement>(null);
|
const iFrameRef = useRef<HTMLIFrameElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function loadContent() {
|
function loadContent() {
|
||||||
|
@ -25,7 +24,7 @@ export function Panel({ html }: { html: string }) {
|
||||||
};
|
};
|
||||||
}, [html]);
|
}, [html]);
|
||||||
return (
|
return (
|
||||||
<div className="panel">
|
<div className="panel" style={{ flex }}>
|
||||||
<iframe srcDoc={iframeHtml} ref={iFrameRef} />
|
<iframe srcDoc={iframeHtml} ref={iFrameRef} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Notification } from "../types";
|
import {Notification} from "../types";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
import { faFileLines } from "@fortawesome/free-solid-svg-icons";
|
import {faFileLines} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
function prettyName(s: string | undefined): string {
|
function prettyName(s: string | undefined): string {
|
||||||
if (!s) {
|
if (!s) {
|
||||||
|
@ -14,14 +14,20 @@ export function TopBar({
|
||||||
unsavedChanges,
|
unsavedChanges,
|
||||||
notifications,
|
notifications,
|
||||||
onClick,
|
onClick,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
}: {
|
}: {
|
||||||
pageName?: string;
|
pageName?: string;
|
||||||
unsavedChanges: boolean;
|
unsavedChanges: boolean;
|
||||||
notifications: Notification[];
|
notifications: Notification[];
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
|
lhs?: React.ReactNode;
|
||||||
|
rhs?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div id="top" onClick={onClick}>
|
<div id="top" onClick={onClick}>
|
||||||
|
{lhs}
|
||||||
|
<div className="main">
|
||||||
<div className="inner">
|
<div className="inner">
|
||||||
<span className={`icon ${unsavedChanges ? "unsaved" : "saved"}`}>
|
<span className={`icon ${unsavedChanges ? "unsaved" : "saved"}`}>
|
||||||
<FontAwesomeIcon icon={faFileLines} />
|
<FontAwesomeIcon icon={faFileLines} />
|
||||||
|
@ -36,5 +42,7 @@ export function TopBar({
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{rhs}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,20 +314,19 @@ export class Editor implements AppEventDispatcher {
|
||||||
mac: "Cmd-i",
|
mac: "Cmd-i",
|
||||||
run: commands.insertMarker("_"),
|
run: commands.insertMarker("_"),
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
key: "Ctrl-p",
|
// key: "Ctrl-p",
|
||||||
mac: "Cmd-p",
|
// mac: "Cmd-p",
|
||||||
run: (): boolean => {
|
// run: (): boolean => {
|
||||||
window.open(location.href, "_blank")!.focus();
|
// window.open(location.href, "_blank")!.focus();
|
||||||
return true;
|
// return true;
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
key: "Ctrl-k",
|
key: "Ctrl-k",
|
||||||
mac: "Cmd-k",
|
mac: "Cmd-k",
|
||||||
run: (): boolean => {
|
run: (): boolean => {
|
||||||
this.viewDispatch({ type: "start-navigate" });
|
this.viewDispatch({ type: "start-navigate" });
|
||||||
// asynchornously will dispatch pageListUpdate event
|
|
||||||
this.space.updatePageListAsync();
|
this.space.updatePageListAsync();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -463,7 +462,7 @@ export class Editor implements AppEventDispatcher {
|
||||||
}, [viewState.currentPage]);
|
}, [viewState.currentPage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={viewState.showRHS ? "rhs-open" : ""}>
|
<>
|
||||||
{viewState.showPageNavigator && (
|
{viewState.showPageNavigator && (
|
||||||
<PageNavigator
|
<PageNavigator
|
||||||
allPages={viewState.allPages}
|
allPages={viewState.allPages}
|
||||||
|
@ -493,7 +492,6 @@ export class Editor implements AppEventDispatcher {
|
||||||
commands={viewState.commands}
|
commands={viewState.commands}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{viewState.showRHS && <Panel html={viewState.rhsHTML} />}
|
|
||||||
<TopBar
|
<TopBar
|
||||||
pageName={viewState.currentPage}
|
pageName={viewState.currentPage}
|
||||||
notifications={viewState.notifications}
|
notifications={viewState.notifications}
|
||||||
|
@ -501,10 +499,28 @@ export class Editor implements AppEventDispatcher {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dispatch({ type: "start-navigate" });
|
dispatch({ type: "start-navigate" });
|
||||||
}}
|
}}
|
||||||
|
rhs={
|
||||||
|
!!viewState.showRHS && (
|
||||||
|
<div className="panel" style={{ flex: viewState.showRHS }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
lhs={
|
||||||
|
!!viewState.showLHS && (
|
||||||
|
<div className="panel" style={{ flex: viewState.showLHS }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
<div id="main">
|
||||||
|
{!!viewState.showLHS && (
|
||||||
|
<Panel html={viewState.lhsHTML} flex={viewState.showLHS} />
|
||||||
|
)}
|
||||||
<div id="editor" />
|
<div id="editor" />
|
||||||
<StatusBar editorView={editor.editorView} />
|
{!!viewState.showRHS && (
|
||||||
|
<Panel html={viewState.rhsHTML} flex={viewState.showRHS} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<StatusBar editorView={editor.editorView} />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Action, AppViewState } from "./types";
|
import {Action, AppViewState} from "./types";
|
||||||
|
|
||||||
export default function reducer(
|
export default function reducer(
|
||||||
state: AppViewState,
|
state: AppViewState,
|
||||||
|
@ -71,15 +71,27 @@ export default function reducer(
|
||||||
case "show-rhs":
|
case "show-rhs":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
showRHS: true,
|
showRHS: action.flex,
|
||||||
rhsHTML: action.html,
|
rhsHTML: action.html,
|
||||||
};
|
};
|
||||||
case "hide-rhs":
|
case "hide-rhs":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
showRHS: false,
|
showRHS: 0,
|
||||||
rhsHTML: "",
|
rhsHTML: "",
|
||||||
};
|
};
|
||||||
|
case "show-lhs":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
showLHS: action.flex,
|
||||||
|
lhsHTML: action.html,
|
||||||
|
};
|
||||||
|
case "hide-lhs":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
showLHS: 0,
|
||||||
|
lhsHTML: "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
@import "constants.scss";
|
@import "constants.scss";
|
||||||
|
|
||||||
div.rhs-open #editor .cm-editor .cm-content {
|
//div.rhs-open #editor .cm-editor .cm-content {
|
||||||
max-width: 550px;
|
// max-width: 550px;
|
||||||
}
|
//}
|
||||||
|
|
||||||
.cm-editor {
|
.cm-editor {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
font-size: var(--ident);
|
font-size: var(--ident);
|
||||||
|
overflow-y: hidden;
|
||||||
|
|
||||||
.cm-content {
|
.cm-content {
|
||||||
font-family: var(--editor-font);
|
font-family: var(--editor-font);
|
||||||
|
@ -15,34 +14,8 @@ div.rhs-open #editor .cm-editor .cm-content {
|
||||||
max-width: $max-editor-width;
|
max-width: $max-editor-width;
|
||||||
}
|
}
|
||||||
|
|
||||||
.other-cursor {
|
&.cm-focused {
|
||||||
display: inline-block;
|
outline: none !important;
|
||||||
width: 2px;
|
|
||||||
margin-right: -2px;
|
|
||||||
height: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cursor-label-container {
|
|
||||||
// display: none;
|
|
||||||
position: relative;
|
|
||||||
top: 2ch;
|
|
||||||
float: left;
|
|
||||||
width: 120px;
|
|
||||||
height: 2.2ch;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
color: #fff;
|
|
||||||
border: gray 1px solid;
|
|
||||||
background-color: purple;
|
|
||||||
// font-size: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cursor-label-container label {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 0.7em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-selectionBackground {
|
.cm-selectionBackground {
|
||||||
|
|
|
@ -14,43 +14,37 @@
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
#root {
|
||||||
position: absolute;
|
display: flex;
|
||||||
top: $top-bar-height + 1px;
|
flex-direction: column;
|
||||||
bottom: $bottom-bar-height;
|
|
||||||
right: 0;
|
|
||||||
width: 50%;
|
|
||||||
z-index: 20;
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
border: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#top {
|
#top {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
height: $top-bar-height;
|
height: $top-bar-height;
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: rgb(213, 213, 213);
|
background-color: rgb(213, 213, 213);
|
||||||
border-bottom: rgb(193, 193, 193) 1px solid;
|
border-bottom: rgb(193, 193, 193) 1px solid;
|
||||||
color: rgb(55, 55, 55);
|
color: rgb(55, 55, 55);
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex: 2;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
padding-top: 12px;
|
|
||||||
max-width: $max-editor-width;
|
max-width: $max-editor-width;
|
||||||
font-size: 28px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
padding-top: 12px;
|
||||||
|
font-size: 28px;
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -78,41 +72,54 @@ body {
|
||||||
color: #e19502;
|
color: #e19502;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor {
|
.panel {
|
||||||
position: absolute;
|
flex: 1;
|
||||||
top: $top-bar-height;
|
|
||||||
bottom: $bottom-bar-height;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.rhs-open #editor {
|
|
||||||
right: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.rhs-open #top .inner {
|
|
||||||
max-width: 550px;
|
|
||||||
padding-right: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: $max-editor-width) {
|
|
||||||
.cm-editor .cm-content {
|
|
||||||
margin: 0 10px !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 0;
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
flex: 1;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
border: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#editor {
|
||||||
|
overflow-y: scroll;
|
||||||
|
flex: 2;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//@media only screen and (max-width: $max-editor-width) {
|
||||||
|
// .cm-editor .cm-content {
|
||||||
|
// margin: 0 10px !important;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
#bottom {
|
#bottom {
|
||||||
height: $bottom-bar-height;
|
height: 25px;
|
||||||
background-color: #ccc;
|
|
||||||
position: fixed;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: rgb(213, 213, 213);
|
background-color: rgb(213, 213, 213);
|
||||||
border-top: rgb(193, 193, 193) 1px solid;
|
border-top: rgb(193, 193, 193) 1px solid;
|
||||||
|
|
||||||
|
|
|
@ -51,17 +51,30 @@ export function editorSyscalls(editor: Editor): SysCallMapping {
|
||||||
"editor.flashNotification": (ctx, message: string) => {
|
"editor.flashNotification": (ctx, message: string) => {
|
||||||
editor.flashNotification(message);
|
editor.flashNotification(message);
|
||||||
},
|
},
|
||||||
"editor.showRhs": (ctx, html: string) => {
|
"editor.showRhs": (ctx, html: string, flex: number) => {
|
||||||
editor.viewDispatch({
|
editor.viewDispatch({
|
||||||
type: "show-rhs",
|
type: "show-rhs",
|
||||||
html: html,
|
flex,
|
||||||
|
html,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"editor.hideRhs": (ctx, html: string) => {
|
"editor.hideRhs": (ctx) => {
|
||||||
editor.viewDispatch({
|
editor.viewDispatch({
|
||||||
type: "hide-rhs",
|
type: "hide-rhs",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
"editor.showLhs": (ctx, html: string, flex: number) => {
|
||||||
|
editor.viewDispatch({
|
||||||
|
type: "show-lhs",
|
||||||
|
flex,
|
||||||
|
html,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"editor.hideLhs": (ctx) => {
|
||||||
|
editor.viewDispatch({
|
||||||
|
type: "hide-lhs",
|
||||||
|
});
|
||||||
|
},
|
||||||
"editor.insertAtPos": (ctx, text: string, pos: number) => {
|
"editor.insertAtPos": (ctx, text: string, pos: number) => {
|
||||||
editor.editorView!.dispatch({
|
editor.editorView!.dispatch({
|
||||||
changes: {
|
changes: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AppCommand } from "./hooks/command";
|
import {AppCommand} from "./hooks/command";
|
||||||
import { PageMeta } from "../common/types";
|
import {PageMeta} from "../common/types";
|
||||||
|
|
||||||
export const slashCommandRegexp = /\/[\w\-]*/;
|
export const slashCommandRegexp = /\/[\w\-]*/;
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@ export type AppViewState = {
|
||||||
showPageNavigator: boolean;
|
showPageNavigator: boolean;
|
||||||
showCommandPalette: boolean;
|
showCommandPalette: boolean;
|
||||||
unsavedChanges: boolean;
|
unsavedChanges: boolean;
|
||||||
showRHS: boolean;
|
showLHS: number; // 0 = hide, > 0 = flex
|
||||||
|
showRHS: number; // 0 = hide, > 0 = flex
|
||||||
rhsHTML: string;
|
rhsHTML: string;
|
||||||
|
lhsHTML: string;
|
||||||
allPages: Set<PageMeta>;
|
allPages: Set<PageMeta>;
|
||||||
commands: Map<string, AppCommand>;
|
commands: Map<string, AppCommand>;
|
||||||
notifications: Notification[];
|
notifications: Notification[];
|
||||||
|
@ -25,8 +27,10 @@ export const initialViewState: AppViewState = {
|
||||||
showPageNavigator: false,
|
showPageNavigator: false,
|
||||||
showCommandPalette: false,
|
showCommandPalette: false,
|
||||||
unsavedChanges: false,
|
unsavedChanges: false,
|
||||||
showRHS: false,
|
showLHS: 0,
|
||||||
rhsHTML: "<h1>Loading...</h1>",
|
showRHS: 0,
|
||||||
|
rhsHTML: "",
|
||||||
|
lhsHTML: "",
|
||||||
allPages: new Set(),
|
allPages: new Set(),
|
||||||
commands: new Map(),
|
commands: new Map(),
|
||||||
notifications: [],
|
notifications: [],
|
||||||
|
@ -44,5 +48,7 @@ export type Action =
|
||||||
| { type: "hide-palette" }
|
| { type: "hide-palette" }
|
||||||
| { type: "show-notification"; notification: Notification }
|
| { type: "show-notification"; notification: Notification }
|
||||||
| { type: "dismiss-notification"; id: number }
|
| { type: "dismiss-notification"; id: number }
|
||||||
| { type: "show-rhs"; html: string }
|
| { type: "show-rhs"; html: string; flex: number }
|
||||||
| { type: "hide-rhs" };
|
| { type: "hide-rhs" }
|
||||||
|
| { type: "show-lhs"; html: string; flex: number }
|
||||||
|
| { type: "hide-lhs" };
|
||||||
|
|
Loading…
Reference in New Issue