Work
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { AppCommand } from "../types";
|
||||
import { isMacLike } from "../util";
|
||||
import { FilterList, Option } from "./filter";
|
||||
import { faPersonRunning } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export function CommandPalette({
|
||||
commands,
|
||||
@@ -20,9 +21,12 @@ export function CommandPalette({
|
||||
console.log("Commands", options);
|
||||
return (
|
||||
<FilterList
|
||||
placeholder="Enter command to run"
|
||||
label="Run"
|
||||
placeholder="Command"
|
||||
options={options}
|
||||
allowNew={false}
|
||||
icon={faPersonRunning}
|
||||
helpText="Start typing the command name to filter results, press <code>Return</code> to run."
|
||||
onSelect={(opt) => {
|
||||
if (opt) {
|
||||
onTrigger(commands.get(opt.name));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export interface Option {
|
||||
name: string;
|
||||
@@ -16,17 +18,23 @@ function magicSorter(a: Option, b: Option): number {
|
||||
export function FilterList({
|
||||
placeholder,
|
||||
options,
|
||||
label,
|
||||
onSelect,
|
||||
onKeyPress,
|
||||
allowNew = false,
|
||||
helpText = "",
|
||||
icon,
|
||||
newHint,
|
||||
}: {
|
||||
placeholder: string;
|
||||
options: Option[];
|
||||
label: string;
|
||||
onKeyPress?: (key: string, currentText: string) => void;
|
||||
onSelect: (option: Option | undefined) => void;
|
||||
allowNew?: boolean;
|
||||
helpText: string;
|
||||
newHint?: string;
|
||||
icon?: IconDefinition;
|
||||
}) {
|
||||
const searchBoxRef = useRef<HTMLInputElement>(null);
|
||||
const [text, setText] = useState("");
|
||||
@@ -81,40 +89,45 @@ export function FilterList({
|
||||
};
|
||||
}, []);
|
||||
|
||||
const returEl = (
|
||||
<div className="filter-container">
|
||||
<input
|
||||
type="text"
|
||||
value={text}
|
||||
placeholder={placeholder}
|
||||
ref={searchBoxRef}
|
||||
onChange={filter}
|
||||
onKeyDown={(e: React.KeyboardEvent) => {
|
||||
console.log("Key up", e.key);
|
||||
if (onKeyPress) {
|
||||
onKeyPress(e.key, text);
|
||||
}
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
setSelectionOption(Math.max(0, selectedOption - 1));
|
||||
break;
|
||||
case "ArrowDown":
|
||||
setSelectionOption(
|
||||
Math.min(matchingOptions.length - 1, selectedOption + 1)
|
||||
);
|
||||
break;
|
||||
case "Enter":
|
||||
onSelect(matchingOptions[selectedOption]);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "Escape":
|
||||
onSelect(undefined);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
className="input"
|
||||
/>
|
||||
|
||||
const returnEl = (
|
||||
<div className="filter-box">
|
||||
<div className="header">
|
||||
<label>{label}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={text}
|
||||
placeholder={placeholder}
|
||||
ref={searchBoxRef}
|
||||
onChange={filter}
|
||||
onKeyDown={(e: React.KeyboardEvent) => {
|
||||
console.log("Key up", e.key);
|
||||
if (onKeyPress) {
|
||||
onKeyPress(e.key, text);
|
||||
}
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
setSelectionOption(Math.max(0, selectedOption - 1));
|
||||
break;
|
||||
case "ArrowDown":
|
||||
setSelectionOption(
|
||||
Math.min(matchingOptions.length - 1, selectedOption + 1)
|
||||
);
|
||||
break;
|
||||
case "Enter":
|
||||
onSelect(matchingOptions[selectedOption]);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "Escape":
|
||||
onSelect(undefined);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="help-text"
|
||||
dangerouslySetInnerHTML={{ __html: helpText }}
|
||||
></div>
|
||||
<div className="result-list">
|
||||
{matchingOptions && matchingOptions.length > 0
|
||||
? matchingOptions.map((option, idx) => (
|
||||
@@ -132,7 +145,10 @@ export function FilterList({
|
||||
onSelect(option);
|
||||
}}
|
||||
>
|
||||
<span className="user-name">{option.name}</span>
|
||||
<span className="icon">
|
||||
{icon && <FontAwesomeIcon icon={icon} />}
|
||||
</span>
|
||||
<span className="name">{option.name}</span>
|
||||
{option.hint && <span className="hint">{option.hint}</span>}
|
||||
</div>
|
||||
))
|
||||
@@ -147,5 +163,5 @@ export function FilterList({
|
||||
});
|
||||
});
|
||||
|
||||
return returEl;
|
||||
return returnEl;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { PageMeta } from "../types";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faFileLines } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export function NavigationBar({
|
||||
currentPage,
|
||||
@@ -8,9 +10,12 @@ export function NavigationBar({
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div id="top">
|
||||
<div className="current-page" onClick={onClick}>
|
||||
» {currentPage?.name}
|
||||
<div id="top" onClick={onClick}>
|
||||
<div className="inner">
|
||||
<span className="icon">
|
||||
<FontAwesomeIcon icon={faFileLines} />
|
||||
</span>
|
||||
<span className="current-page">{currentPage?.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PageMeta } from "../types";
|
||||
import { FilterList, Option } from "./filter";
|
||||
import { faFileLines } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export function PageNavigator({
|
||||
allPages,
|
||||
@@ -28,9 +29,12 @@ export function PageNavigator({
|
||||
}
|
||||
return (
|
||||
<FilterList
|
||||
placeholder=""
|
||||
placeholder="Page"
|
||||
label="Open"
|
||||
options={options}
|
||||
icon={faFileLines}
|
||||
allowNew={true}
|
||||
helpText="Start typing the page name to filter results, press <code>Return</code> to open."
|
||||
newHint="Create page"
|
||||
onSelect={(opt) => {
|
||||
onNavigate(opt?.name);
|
||||
|
||||
+24
-18
@@ -57,6 +57,7 @@ import {
|
||||
import { safeRun } from "./util";
|
||||
import { Indexer } from "./indexer";
|
||||
import { IPageNavigator, PathPageNavigator } from "./navigator";
|
||||
import { smartQuoteKeymap } from "./smart_quotes";
|
||||
|
||||
class PageState {
|
||||
editorState: EditorState;
|
||||
@@ -123,7 +124,7 @@ export class Editor implements AppEventDispatcher {
|
||||
}
|
||||
|
||||
async loadPlugins() {
|
||||
const system = new BrowserSystem("plugin");
|
||||
const system = new BrowserSystem("/plugin");
|
||||
system.registerSyscalls(
|
||||
dbSyscalls,
|
||||
editorSyscalls(this),
|
||||
@@ -222,6 +223,7 @@ export class Editor implements AppEventDispatcher {
|
||||
{ selector: "FencedCode", class: "line-fenced-code" },
|
||||
]),
|
||||
keymap.of([
|
||||
...smartQuoteKeymap,
|
||||
...closeBracketsKeymap,
|
||||
...standardKeymap,
|
||||
...searchKeymap,
|
||||
@@ -248,8 +250,8 @@ export class Editor implements AppEventDispatcher {
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "Ctrl-e",
|
||||
mac: "Cmd-e",
|
||||
key: "Ctrl-k",
|
||||
mac: "Cmd-k",
|
||||
run: (target): boolean => {
|
||||
this.viewDispatch({ type: "start-navigate" });
|
||||
return true;
|
||||
@@ -302,7 +304,6 @@ export class Editor implements AppEventDispatcher {
|
||||
ctx: CompletionContext
|
||||
): Promise<CompletionResult | null> {
|
||||
let allCompletionResults = await this.dispatchAppEvent("editor:complete");
|
||||
// console.log("All results", allCompletionResults);
|
||||
if (allCompletionResults.length === 1) {
|
||||
return allCompletionResults[0];
|
||||
} else if (allCompletionResults.length > 1) {
|
||||
@@ -368,13 +369,14 @@ export class Editor implements AppEventDispatcher {
|
||||
console.log("Page not modified, skipping saving");
|
||||
return;
|
||||
}
|
||||
// Write to file system
|
||||
let text = editorState.sliceDoc();
|
||||
let pageMeta = await this.space.writePage(this.currentPage.name, text);
|
||||
// Write to the space
|
||||
const pageName = this.currentPage.name;
|
||||
const text = editorState.sliceDoc();
|
||||
let pageMeta = await this.space.writePage(pageName, text);
|
||||
|
||||
// Update in open page cache
|
||||
this.openPages.set(
|
||||
this.currentPage.name,
|
||||
pageName,
|
||||
new PageState(editorState, this.editorView!.scrollDOM.scrollTop, pageMeta)
|
||||
);
|
||||
|
||||
@@ -422,10 +424,10 @@ export class Editor implements AppEventDispatcher {
|
||||
console.log("File changed on disk, reloading");
|
||||
let pageData = await this.space.readPage(currentPageName);
|
||||
this.openPages.set(
|
||||
newPageMeta.name,
|
||||
currentPageName,
|
||||
new PageState(this.createEditorState(pageData.text), 0, newPageMeta)
|
||||
);
|
||||
await this.loadPage(currentPageName);
|
||||
await this.loadPage(currentPageName, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,11 +435,11 @@ export class Editor implements AppEventDispatcher {
|
||||
this.editorView!.focus();
|
||||
}
|
||||
|
||||
async navigate(name: string) {
|
||||
await this.pageNavigator.navigate(name);
|
||||
navigate(name: string) {
|
||||
this.pageNavigator.navigate(name);
|
||||
}
|
||||
|
||||
async loadPage(pageName: string) {
|
||||
async loadPage(pageName: string, checkNewVersion: boolean = true) {
|
||||
let pageState = this.openPages.get(pageName);
|
||||
if (!pageState) {
|
||||
let pageData = await this.space.readPage(pageName);
|
||||
@@ -447,11 +449,8 @@ export class Editor implements AppEventDispatcher {
|
||||
pageData.meta
|
||||
);
|
||||
this.openPages.set(pageName, pageState!);
|
||||
} else {
|
||||
// Loaded page from in-mory cache, let's async see if this page hasn't been updated
|
||||
this.checkForNewVersion(pageState.meta).catch((e) => {
|
||||
console.error("Failed to check for new version");
|
||||
});
|
||||
// Freshly loaded, no need to check for a new version either way
|
||||
checkNewVersion = false;
|
||||
}
|
||||
this.editorView!.setState(pageState!.editorState);
|
||||
this.editorView!.scrollDOM.scrollTop = pageState!.scrollTop;
|
||||
@@ -470,6 +469,13 @@ export class Editor implements AppEventDispatcher {
|
||||
) {
|
||||
await this.indexPage(pageState.editorState.sliceDoc(), pageState.meta);
|
||||
}
|
||||
|
||||
if (checkNewVersion) {
|
||||
// Loaded page from in-memory cache, let's async see if this page hasn't been updated
|
||||
this.checkForNewVersion(pageState.meta).catch((e) => {
|
||||
console.error("Failed to check for new version");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ViewComponent(): React.ReactElement {
|
||||
|
||||
@@ -43,8 +43,8 @@ self.addEventListener("message", (event) => {
|
||||
let data = messageEvent.data;
|
||||
switch (data.type) {
|
||||
case "boot":
|
||||
console.log("Booting", `./${data.prefix}/function/${data.name}`);
|
||||
importScripts(`./${data.prefix}/function/${data.name}`);
|
||||
console.log("Booting", `${data.prefix}/function/${data.name}`);
|
||||
importScripts(`${data.prefix}/function/${data.name}`);
|
||||
self.postMessage({
|
||||
type: "inited",
|
||||
});
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -3,8 +3,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Page</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<link rel="stylesheet" href="styles/main.scss" />
|
||||
<script type="module" src="boot.ts"></script>
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"short_name": "Nugget",
|
||||
"name": "Nugget",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./images/logo.png",
|
||||
"type": "image/png",
|
||||
"sizes": "1024x1024"
|
||||
}
|
||||
],
|
||||
"capture_links": "new-client",
|
||||
"start_url": "/start",
|
||||
"display": "standalone",
|
||||
"scope": "/",
|
||||
"theme_color": "#000",
|
||||
"description": "Note taking for winners"
|
||||
}
|
||||
@@ -17,7 +17,6 @@ function decodePageUrl(url: string): string {
|
||||
export class PathPageNavigator implements IPageNavigator {
|
||||
navigationResolve?: (value: undefined) => void;
|
||||
async navigate(page: string) {
|
||||
console.log("Pushing state", page);
|
||||
window.history.pushState({ page: page }, page, `/${encodePageUrl(page)}`);
|
||||
window.dispatchEvent(new PopStateEvent("popstate"));
|
||||
await new Promise<undefined>((resolve) => {
|
||||
@@ -27,7 +26,10 @@ export class PathPageNavigator implements IPageNavigator {
|
||||
}
|
||||
subscribe(pageLoadCallback: (pageName: string) => Promise<void>): void {
|
||||
const cb = () => {
|
||||
console.log("State popped", this.getCurrentPage());
|
||||
const gotoPage = this.getCurrentPage();
|
||||
if (!gotoPage) {
|
||||
return;
|
||||
}
|
||||
safeRun(async () => {
|
||||
await pageLoadCallback(this.getCurrentPage());
|
||||
if (this.navigationResolve) {
|
||||
|
||||
@@ -46,6 +46,7 @@ export class BrowserSystem extends System {
|
||||
new URL("../plugin_sw.ts", import.meta.url),
|
||||
{
|
||||
type: "module",
|
||||
scope: "/",
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export class FunctionWorker {
|
||||
// type: "classic",
|
||||
// });
|
||||
let worker = window.Worker;
|
||||
this.worker = new worker("function_worker.js");
|
||||
this.worker = new worker("/function_worker.js");
|
||||
|
||||
// console.log("Starting worker", this.worker);
|
||||
this.worker.onmessage = this.onmessage.bind(this);
|
||||
|
||||
@@ -4,7 +4,7 @@ export default function reducer(
|
||||
state: AppViewState,
|
||||
action: Action
|
||||
): AppViewState {
|
||||
console.log("Got action", action);
|
||||
// console.log("Got action", action);
|
||||
switch (action.type) {
|
||||
case "page-loaded":
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { KeyBinding } from "@codemirror/view";
|
||||
|
||||
// TODO: Add support for selection (put quotes around or create blockquote block?)
|
||||
function keyBindingForQuote(
|
||||
quote: string,
|
||||
left: string,
|
||||
right: string
|
||||
): KeyBinding {
|
||||
return {
|
||||
key: quote,
|
||||
run: (target): boolean => {
|
||||
let cursorPos = target.state.selection.main.from;
|
||||
let chBefore = target.state.sliceDoc(cursorPos - 1, cursorPos);
|
||||
let quote = right;
|
||||
if (/\W/.exec(chBefore) && !/[!\?,\.\-=“]/.exec(chBefore)) {
|
||||
quote = left;
|
||||
}
|
||||
target.dispatch({
|
||||
changes: {
|
||||
insert: quote,
|
||||
from: cursorPos,
|
||||
},
|
||||
selection: {
|
||||
anchor: cursorPos + 1,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const smartQuoteKeymap: KeyBinding[] = [
|
||||
keyBindingForQuote('"', "“", "”"),
|
||||
keyBindingForQuote("'", "‘", "’"),
|
||||
];
|
||||
@@ -10,6 +10,7 @@ export interface Space {
|
||||
|
||||
export class HttpRemoteSpace implements Space {
|
||||
url: string;
|
||||
|
||||
constructor(url: string) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
:root {
|
||||
--ident: 18px;
|
||||
/* --editor-font: "Avenir"; */
|
||||
--editor-font: "Menlo";
|
||||
--top-bar-bg: rgb(41, 41, 41);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#top {
|
||||
height: 40px;
|
||||
background-color: var(--top-bar-bg);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
#bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 25px;
|
||||
background-color: var(--top-bar-bg);
|
||||
color: #eee;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-family: var(--editor-font);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#editor {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
bottom: 40px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: var(--ident);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
.cm-editor .cm-content {
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-editor .cm-content {
|
||||
font-family: var(--editor-font);
|
||||
margin: auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.cm-editor .cm-selectionBackground {
|
||||
background-color: #d7e1f6 !important;
|
||||
}
|
||||
|
||||
.cm-editor .h1 {
|
||||
font-size: 1.5em;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-editor .cm-line.line-h1 {
|
||||
display: block;
|
||||
background-color: rgba(0, 15, 52, 0.6);
|
||||
}
|
||||
|
||||
.cm-editor .h1.meta {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.cm-editor .h2 {
|
||||
font-size: 1.2em;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-editor .cm-line.line-h2 {
|
||||
display: block;
|
||||
background-color: rgba(0, 15, 52, 0.6);
|
||||
}
|
||||
|
||||
.cm-editor .h2.meta {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
/* .cm-editor .cm-line {
|
||||
padding-left: 50px;
|
||||
max-width: 800px;
|
||||
} */
|
||||
|
||||
.cm-editor .line-code {
|
||||
background-color: #efefef;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.cm-editor .line-fenced-code {
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.cm-editor .meta {
|
||||
color: #650007;
|
||||
}
|
||||
|
||||
.cm-editor .line-blockquote {
|
||||
background-color: #eee;
|
||||
color: #676767;
|
||||
text-indent: calc(-1 * (var(--ident) + 3px));
|
||||
padding-left: var(--ident);
|
||||
}
|
||||
|
||||
.cm-editor .emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.cm-editor .strong {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.cm-editor .link:not(.meta, .url) {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.cm-editor .link.url {
|
||||
color: #7e7d7d;
|
||||
}
|
||||
.cm-editor .url:not(.link) {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.cm-editor .wiki-link-page {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.cm-editor .wiki-link {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.cm-editor .mention {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.cm-editor .tag {
|
||||
color: #8d8d8d;
|
||||
}
|
||||
|
||||
.cm-editor .line-li {
|
||||
text-indent: calc(-1 * var(--ident) - 3px);
|
||||
margin-left: var(--ident);
|
||||
}
|
||||
|
||||
.cm-editor .task-marker {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.current-page {
|
||||
font-family: var(--editor-font);
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
font-family: var(--editor-font);
|
||||
display: block;
|
||||
border: #333 1px solid;
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
left: 25px;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.filter-container .result-list {
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.filter-container input {
|
||||
font-family: var(--editor-font);
|
||||
width: 100%;
|
||||
/* border: 1px #333 solid; */
|
||||
background-color: var(--top-bar-bg);
|
||||
color: #eee;
|
||||
border: 0;
|
||||
padding: 3px;
|
||||
outline: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.filter-container .option,
|
||||
.filter-container .selected-option {
|
||||
padding: 3px 3px 3px 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.filter-container .selected-option {
|
||||
background-color: #b1b1b1;
|
||||
}
|
||||
|
||||
.filter-container .hint {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
color: #333;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
.cm-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: var(--ident);
|
||||
|
||||
.cm-content {
|
||||
font-family: var(--editor-font);
|
||||
margin: auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.cm-selectionBackground {
|
||||
background-color: #d7e1f6 !important;
|
||||
}
|
||||
|
||||
.h1 {
|
||||
font-size: 1.5em;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-line.line-h1 {
|
||||
display: block;
|
||||
background-color: rgba(0, 15, 52, 0.6);
|
||||
}
|
||||
|
||||
.h1.meta {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.h2 {
|
||||
font-size: 1.2em;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-line.line-h2 {
|
||||
display: block;
|
||||
background-color: rgba(0, 15, 52, 0.6);
|
||||
}
|
||||
|
||||
.h2.meta {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
/* Color list item this way */
|
||||
.line-li .meta {
|
||||
color: rgb(0, 123, 19);
|
||||
}
|
||||
/* Then undo other meta */
|
||||
.line-li .meta ~ .meta {
|
||||
color: #650007;
|
||||
}
|
||||
|
||||
.line-code {
|
||||
background-color: #efefef;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.line-fenced-code {
|
||||
background-color: #efefef;
|
||||
}
|
||||
|
||||
.meta {
|
||||
color: #650007;
|
||||
}
|
||||
|
||||
.line-blockquote {
|
||||
background-color: #eee;
|
||||
color: #676767;
|
||||
text-indent: calc(-1 * (var(--ident) + 3px));
|
||||
padding-left: var(--ident);
|
||||
}
|
||||
|
||||
.emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.strong {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.link:not(.meta, .url) {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.link.url {
|
||||
color: #7e7d7d;
|
||||
}
|
||||
.url:not(.link) {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.wiki-link-page {
|
||||
color: #0330cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.wiki-link {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.mention {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: #8d8d8d;
|
||||
}
|
||||
|
||||
.line-li {
|
||||
text-indent: calc(-1 * var(--ident) - 3px);
|
||||
margin-left: var(--ident);
|
||||
}
|
||||
|
||||
.task-marker {
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
.filter-box {
|
||||
position: absolute;
|
||||
font-family: var(--ui-font);
|
||||
margin: auto;
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
background-color: #fff;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
max-height: 290px;
|
||||
overflow: auto;
|
||||
z-index: 100;
|
||||
border: rgb(103, 103, 103) 1px solid;
|
||||
border-radius: 8px;
|
||||
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
|
||||
|
||||
label {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.header {
|
||||
border-bottom: 1px rgb(108, 108, 108) solid;
|
||||
padding: 13px 10px 10px 10px;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
background-color: #eee;
|
||||
border-bottom: 1px rgb(108, 108, 108) solid;
|
||||
padding: 5px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.result-list {
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
background-color: white;
|
||||
|
||||
.icon {
|
||||
padding: 0 8px 0 5px;
|
||||
}
|
||||
.name {
|
||||
padding-top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: "Arial";
|
||||
background: transparent;
|
||||
color: #000;
|
||||
border: 0;
|
||||
padding: 3px;
|
||||
outline: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: rgb(199, 199, 199);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.option,
|
||||
.selected-option {
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected-option {
|
||||
background-color: var(--highlight-color);
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.option .hint,
|
||||
.selected-option .hint {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-top: -4px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
color: #eee;
|
||||
background-color: #212476;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
@use "editor.scss";
|
||||
@use "filter_box.scss";
|
||||
|
||||
:root {
|
||||
--ident: 18px;
|
||||
/* --editor-font: "Avenir"; */
|
||||
--editor-font: "Menlo";
|
||||
--ui-font: "Arial";
|
||||
--top-bar-bg: rgb(41, 41, 41);
|
||||
--highlight-color: #464cfc;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#top {
|
||||
height: 55px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgb(213, 213, 213);
|
||||
border-bottom: rgb(193, 193, 193) 1px solid;
|
||||
color: rgb(55, 55, 55);
|
||||
|
||||
.inner {
|
||||
padding-top: 12px;
|
||||
max-width: 800px;
|
||||
font-size: 28px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.current-page {
|
||||
font-family: var(--ui-font);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding-left: 5px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 20px;
|
||||
background-color: rgb(232, 232, 232);
|
||||
color: rgb(79, 78, 78);
|
||||
border-top: rgb(186, 186, 186) 1px solid;
|
||||
margin: 0;
|
||||
padding: 5px 10px;
|
||||
font-family: var(--ui-font);
|
||||
font-size: 0.9em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#editor {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
bottom: 30px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 800px) {
|
||||
.cm-editor .cm-content {
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user