Skip to content

Commit

Permalink
feat: add search box
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentdchan committed Sep 25, 2022
1 parent 3b01a07 commit c9c3511
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 58 deletions.
2 changes: 2 additions & 0 deletions packages/blocky-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
"blocky-data": "workspace:*",
"blocky-preact": "workspace:*",
"highlight.js": "^11.6.0",
"is-hotkey": "^0.2.0",
"marked": "^4.0.18",
"preact-router": "^4.1.0"
},
"devDependencies": {
"@babel/core": "^7.18.2",
"@preact/preset-vite": "^2.2.0",
"@types/is-hotkey": "^0.1.7",
"@types/marked": "^4.0.5",
"@types/node": "^17.0.41",
"preact": "^10.7.3",
Expand Down
15 changes: 13 additions & 2 deletions packages/blocky-example/src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
border-right-style: solid;
border-right-width: 1px;
border-right-color: grey;
flex-shrink: 0;

header {
padding: 0px 28px;
Expand Down Expand Up @@ -45,6 +46,7 @@
overflow-x: hidden;
position: relative;
display: flex;
flex: 1;
}

body {
Expand Down Expand Up @@ -81,8 +83,7 @@ body {
.blocky-example-editor-container {
flex: 50%;
max-width: 50%;
overflow-x: scroll;
overflow-y: scroll;
position: relative;

&.left {
border-right-style: solid;
Expand All @@ -91,6 +92,16 @@ body {
}
}

.blocky-example-content-container {
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
overflow-x: scroll;
overflow-y: scroll;
}

.blocky-example-user {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin-top: 14px;
Expand Down
122 changes: 66 additions & 56 deletions packages/blocky-example/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, createRef } from "preact";
import { Component, createRef, RefObject } from "preact";
import { useEffect, useState } from "preact/compat";
import { EditorController, darkTheme, type IPlugin } from "blocky-core";
import {
BlockyEditor,
Expand All @@ -11,6 +12,7 @@ import makeCodeTextPlugin from "blocky-core/dist/plugins/codeTextPlugin";
import makeBulletListPlugin from "blocky-core/dist/plugins/bulletListPlugin";
import makeHeadingsPlugin from "blocky-core/dist/plugins/headingsPlugin";
import AppLogo from "@pkg/components/appLogo";
import SearchBox from "@pkg/components/searchBox";
import { makeImageBlockPlugin } from "./plugins/imageBlock";
import { makeCommandPanelPlugin } from "./plugins/commandPanel";
import { makeAtPanelPlugin } from "./plugins/atPanel";
Expand All @@ -20,6 +22,7 @@ import TianShuiWeiImage from "./tianshuiwei.jpg";
import { ReadMeContent } from "./readme";
import { Link } from "preact-router/match";
import { ThemeSwitch, Theme } from "./themeSwitch";
import { isHotkey } from "is-hotkey";
import "blocky-core/css/styled-text-plugin.css";
import "blocky-core/css/blocky-core.css";
import "./app.scss";
Expand Down Expand Up @@ -192,40 +195,16 @@ class App extends Component<unknown> {
</div>
</div>
<div className="blocky-example-container">
<div
ref={this.containerLeftRef}
<BlockyEditorWithSearchBoxAndTitle
containerRef={this.containerLeftRef}
className="blocky-example-editor-container left"
>
<div className="blocky-example-image">
<img src={TianShuiWeiImage} />
</div>
<Theme.Consumer>
{(options) => (
<BlockyEditorWithTheme
controller={this.editorControllerLeft}
darkMode={options.darkMode}
autoFocus
/>
)}
</Theme.Consumer>
</div>
<div
ref={this.containerRightRef}
controller={this.editorControllerLeft}
/>
<BlockyEditorWithSearchBoxAndTitle
containerRef={this.containerRightRef}
className="blocky-example-editor-container right"
>
<div className="blocky-example-image">
<img src={TianShuiWeiImage} />
</div>
<Theme.Consumer>
{(options) => (
<BlockyEditorWithTheme
controller={this.editorControllerRight}
darkMode={options.darkMode}
ignoreInitEmpty
/>
)}
</Theme.Consumer>
</div>
controller={this.editorControllerRight}
/>
</div>
</div>
);
Expand All @@ -239,32 +218,63 @@ interface BlockyEditorWithThemeProps {
darkMode?: boolean;
}

class BlockyEditorWithTheme extends Component<BlockyEditorWithThemeProps> {
componentDidMount() {
if (this.props.darkMode) {
this.props.controller.themeData = darkTheme;
function BlockyEditorWithTheme(props: BlockyEditorWithThemeProps) {
const { darkMode, controller } = props;
useEffect(() => {
if (darkMode) {
controller.themeData = darkTheme;
} else {
controller.themeData = undefined;
}
}
}, [darkMode]);
return (
<BlockyEditor
controller={props.controller}
autoFocus={props.autoFocus}
ignoreInitEmpty={props.ignoreInitEmpty}
/>
);
}

componentWillReceiveProps(nextProps: BlockyEditorWithThemeProps) {
if (this.props.darkMode !== nextProps.darkMode) {
if (nextProps.darkMode) {
nextProps.controller.themeData = darkTheme;
} else {
nextProps.controller.themeData = undefined;
}
}
}
interface BlockyEditorWithSearchBoxAndTitleProps {
containerRef: RefObject<HTMLDivElement>;
className: string;
controller: EditorController;
}

render(props: BlockyEditorWithThemeProps) {
return (
<BlockyEditor
controller={props.controller}
autoFocus={props.autoFocus}
ignoreInitEmpty={props.ignoreInitEmpty}
/>
);
}
function BlockyEditorWithSearchBoxAndTitle(
props: BlockyEditorWithSearchBoxAndTitleProps
) {
const { controller } = props;
const [showSearchBox, setShowSearchBox] = useState(false);
useEffect(() => {
const disposable = controller.editor?.keyDown.on((e: KeyboardEvent) => {
if (isHotkey("mod+f", e)) {
e.preventDefault();
setShowSearchBox(true);
}
});
return () => disposable?.dispose();
}, [controller]);
return (
<div ref={props.containerRef} className={props.className}>
{showSearchBox && <SearchBox onClose={() => setShowSearchBox(false)} />}
<div className="blocky-example-content-container">
<div className="blocky-example-image">
<img src={TianShuiWeiImage} />
</div>
<Theme.Consumer>
{(options) => (
<BlockyEditorWithTheme
controller={controller}
darkMode={options.darkMode}
ignoreInitEmpty
/>
)}
</Theme.Consumer>
</div>
</div>
);
}

export default App;
3 changes: 3 additions & 0 deletions packages/blocky-example/src/components/searchBox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import SearchBox from "./searchBox";

export default SearchBox;
34 changes: 34 additions & 0 deletions packages/blocky-example/src/components/searchBox/searchBox.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

.blocky-example-search-box {
display: flex;
height: 28px;
background-color: var(--bg-color);
position: absolute;
top: 12px;
right: 18px;
padding: 4px 8px;
border-radius: 4px;
z-index: 10;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;

input {
background-color: transparent;
border: none;
color: var(--primary-text-color);

&:focus {
outline: none;
}
}

.result-display {
padding: 0px 8px;
line-height: 28px;
font-size: 12px;
color: var(--primary-text-color);
}

button {
margin-left: 2px;
}
}
61 changes: 61 additions & 0 deletions packages/blocky-example/src/components/searchBox/searchBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Component, createRef, JSX } from "preact";
import Button from "@pkg/components/button";
import { flattenDisposable, IDisposable } from "blocky-common/es/disposable";
import "./searchBox.scss";
import { listenWindow } from "blocky-common/es/dom";

export interface SearchBoxProps {
onClose?: () => void;
}

class SearchBox extends Component<SearchBoxProps> {
private inputRef = createRef<HTMLInputElement>();
private disposables: IDisposable[] = [];
private isFocused = false;

override componentDidMount(): void {
window.requestAnimationFrame(() => {
this.inputRef.current!.focus();
});

this.disposables.push(
listenWindow("keydown", (e: KeyboardEvent) => {
if (this.isFocused) {
this.props.onClose?.();
}
})
);
}

componentWillUnmount(): void {
flattenDisposable(this.disposables).dispose();
}

handleInputFocus = () => {
this.isFocused = true;
};

handleInputBlur = () => {
this.isFocused = false;
};

override render(props: SearchBoxProps) {
return (
<div className="blocky-example-search-box">
<input
onFocus={this.handleInputFocus}
onBlur={this.handleInputBlur}
placeholder="Find"
ref={this.inputRef}
onKeyDown={(e) => console.log(e)}
/>
<div className="result-display">No results</div>
<Button>{"<"}</Button>
<Button>{">"}</Button>
<Button onClick={props.onClose}>{"X"}</Button>
</div>
);
}
}

export default SearchBox;
4 changes: 4 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c9c3511

Please sign in to comment.