Flexible LHS and RHS with flex

pull/3/head
Zef Hemel 2022-04-04 18:33:13 +02:00
parent a7cd3ea7e0
commit 1b0048cdcf
11 changed files with 193 additions and 149 deletions

View File

@ -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);
} }

View File

@ -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

View File

@ -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() {

View File

@ -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>
); );

View File

@ -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>
); );
} }

View File

@ -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} />
</>
); );
} }

View File

@ -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;
} }

View File

@ -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 {

View File

@ -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;

View File

@ -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: {

View File

@ -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" };