feat: layout style(1)

This commit is contained in:
email 2022-03-20 20:02:48 +08:00
parent 8ad98291eb
commit 2b5ee78397
34 changed files with 70 additions and 194 deletions

View File

@ -10,8 +10,7 @@
"dependencies": {
"lodash-es": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"tiny-undo": "^0.0.8"
"react-dom": "^17.0.2"
},
"devDependencies": {
"@types/lodash-es": "^4.17.5",

View File

@ -1,7 +1,4 @@
import { forwardRef, ReactNode, useCallback, useContext, useEffect, useImperativeHandle, useRef } from "react";
import TinyUndo from "tiny-undo";
import appContext from "../../stores/appContext";
import { storage } from "../../helpers/storage";
import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef } from "react";
import useRefresh from "../../hooks/useRefresh";
import Only from "../common/OnlyWhen";
import "../../less/editor.less";
@ -28,9 +25,6 @@ interface EditorProps {
// eslint-disable-next-line react/display-name
const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRefActions>) => {
const {
globalState: { useTinyUndoHistoryCache },
} = useContext(appContext);
const {
className,
initialContent,
@ -42,59 +36,14 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
onContentChange: handleContentChangeCallback,
} = props;
const editorRef = useRef<HTMLTextAreaElement>(null);
const tinyUndoRef = useRef<TinyUndo | null>(null);
// NOTE: auto-justify textarea height
const refresh = useRefresh();
useEffect(() => {
if (!editorRef.current) {
return;
}
if (initialContent) {
if (editorRef.current && initialContent) {
editorRef.current.value = initialContent;
refresh();
}
}, []);
useEffect(() => {
if (useTinyUndoHistoryCache) {
if (!editorRef.current) {
return;
}
const { tinyUndoActionsCache, tinyUndoIndexCache } = storage.get(["tinyUndoActionsCache", "tinyUndoIndexCache"]);
tinyUndoRef.current = new TinyUndo(editorRef.current, {
interval: 5000,
initialActions: tinyUndoActionsCache,
initialIndex: tinyUndoIndexCache,
});
tinyUndoRef.current.subscribe((actions, index) => {
storage.set({
tinyUndoActionsCache: actions,
tinyUndoIndexCache: index,
});
});
return () => {
tinyUndoRef.current?.destroy();
};
} else {
tinyUndoRef.current?.destroy();
tinyUndoRef.current = null;
storage.remove(["tinyUndoActionsCache", "tinyUndoIndexCache"]);
}
}, [useTinyUndoHistoryCache]);
useEffect(() => {
if (editorRef.current) {
editorRef.current.style.height = "auto";
editorRef.current.style.height = (editorRef.current.scrollHeight ?? 0) + "px";
}
}, [editorRef.current?.value]);
useImperativeHandle(
ref,
() => ({
@ -111,13 +60,11 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
editorRef.current.value =
prevValue.slice(0, editorRef.current.selectionStart) + rawText + prevValue.slice(editorRef.current.selectionStart);
handleContentChangeCallback(editorRef.current.value);
refresh();
},
setContent: (text: string) => {
if (editorRef.current) {
editorRef.current.value = text;
handleContentChangeCallback(editorRef.current.value);
refresh();
}
},
getContent: (): string => {
@ -140,7 +87,6 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
handleCommonConfirmBtnClick();
}
}
refresh();
}, []);
const handleCommonConfirmBtnClick = useCallback(() => {
@ -150,9 +96,6 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef<EditorRef
handleConfirmBtnClickCallback(editorRef.current.value);
editorRef.current.value = "";
refresh();
// After confirm btn clicked, tiny-undo should reset state(clear actions and index)
tinyUndoRef.current?.resetState();
}, []);
const handleCommonCancelBtnClick = useCallback(() => {

View File

@ -276,7 +276,7 @@ const MemoEditor: React.FC<Props> = () => {
);
return (
<div className={"memo-editor-wrapper " + (showEditStatus ? "edit-ing" : "")}>
<div className={"memo-editor-container " + (showEditStatus ? "edit-ing" : "")}>
<p className={"tip-text " + (showEditStatus ? "" : "hidden")}>Editting...</p>
<Editor
ref={editorRef}

View File

@ -6,7 +6,7 @@ import utils from "../helpers/utils";
import { checkShouldShowMemoWithFilters } from "../helpers/filter";
import Memo from "./Memo";
import toastHelper from "./Toast";
import "../less/memolist.less";
import "../less/memo-list.less";
interface Props {}
@ -105,7 +105,7 @@ const MemoList: React.FC<Props> = () => {
}, []);
return (
<div className={`memolist-wrapper ${isFetching ? "" : "completed"}`} onClick={handleMemoListClick} ref={wrapperElement}>
<div className={`memo-list-container ${isFetching ? "" : "completed"}`} onClick={handleMemoListClick} ref={wrapperElement}>
{shownMemos.map((memo) => (
<Memo key={`${memo.id}-${memo.updatedAt}`} memo={memo} />
))}

View File

@ -33,7 +33,7 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
};
const handleMemosTrashBtnClick = () => {
locationService.pushHistory("/recycle");
locationService.pushHistory("/trash");
};
const handleAboutBtnClick = () => {

View File

@ -9,16 +9,10 @@ interface Props {}
const PreferencesSection: React.FC<Props> = () => {
const { globalState } = useContext(appContext);
const { useTinyUndoHistoryCache, shouldHideImageUrl, shouldSplitMemoWord, shouldUseMarkdownParser } = globalState;
const { shouldHideImageUrl, shouldSplitMemoWord, shouldUseMarkdownParser } = globalState;
const demoMemoContent = "👋 Hiya, welcome to memos!\n* ✨ **Open source project**;\n* 😋 What do you think;\n* 📑 Tell me something plz;";
const handleOpenTinyUndoChanged = () => {
globalStateService.setAppSetting({
useTinyUndoHistoryCache: !useTinyUndoHistoryCache,
});
};
const handleSplitWordsValueChanged = () => {
globalStateService.setAppSetting({
shouldSplitMemoWord: !shouldSplitMemoWord,
@ -83,18 +77,6 @@ const PreferencesSection: React.FC<Props> = () => {
<img className="icon-img" src={shouldHideImageUrl ? "/icons/checkbox-active.svg" : "/icons/checkbox.svg"} />
</label>
</div>
<div className="section-container preferences-section-container">
<p className="title-text">Editor Extensions</p>
<label className="form-label checkbox-form-label" onClick={handleOpenTinyUndoChanged}>
<span className="normal-text">
Use{" "}
<a target="_blank" href="https://github.com/boojack/tiny-undo" onClick={(e) => e.stopPropagation()} rel="noreferrer">
tiny-undo
</a>
</span>
<img className="icon-img" src={useTinyUndoHistoryCache ? "/icons/checkbox-active.svg" : "/icons/checkbox.svg"} />
</label>
</div>
<div className="section-container">
<p className="title-text">Others</p>
<div className="w-full flex flex-row justify-start items-center">

View File

@ -67,11 +67,14 @@ const ShortcutContainer: React.FC<ShortcutContainerProps> = (props: ShortcutCont
const { shortcut, isActive } = props;
const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false);
const handleQueryClick = () => {
console.log(props);
const handleShortcutClick = () => {
console.log("here");
if (isActive) {
locationService.setMemoShortcut("");
} else {
if (!["/", "/recycle"].includes(locationService.getState().pathname)) {
if (!["/", "/trash"].includes(locationService.getState().pathname)) {
locationService.setPathname("/");
}
locationService.setMemoShortcut(shortcut.id);
@ -125,7 +128,7 @@ const ShortcutContainer: React.FC<ShortcutContainerProps> = (props: ShortcutCont
return (
<>
<div className={`shortcut-container ${isActive ? "active" : ""}`} onClick={handleQueryClick}>
<div className={`shortcut-container ${isActive ? "active" : ""}`} onClick={handleShortcutClick}>
<div className="shortcut-text-container">
<span className="icon-text">#</span>
<span className="shortcut-text">{shortcut.title}</span>

View File

@ -1,7 +1,6 @@
import { useRef } from "react";
import UserBanner from "./UserBanner";
import ShortcutList from "./ShortcutList";
import TagList from "./TagList";
import UsageHeatMap from "./UsageHeatMap";
import "../less/siderbar.less";
@ -15,7 +14,6 @@ const Sidebar: React.FC<Props> = () => {
<UserBanner />
<UsageHeatMap />
<ShortcutList />
<TagList />
</aside>
);
};

View File

@ -101,7 +101,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
locationService.setTagQuery("");
} else {
utils.copyTextToClipboard(`#${tag.text} `);
if (!["/", "/recycle"].includes(locationService.getState().pathname)) {
if (!["/", "/trash"].includes(locationService.getState().pathname)) {
locationService.setPathname("/");
}
locationService.setTagQuery(tag.text);

View File

@ -76,7 +76,7 @@ const UsageHeatMap: React.FC<Props> = () => {
locationService.setFromAndToQuery(0, 0);
setCurrentStat(null);
} else if (item.count > 0) {
if (!["/", "/recycle"].includes(locationService.getState().pathname)) {
if (!["/", "/trash"].includes(locationService.getState().pathname)) {
locationService.setPathname("/");
}
locationService.setFromAndToQuery(item.timestamp, item.timestamp + DAILY_TIMESTAMP);

View File

@ -1,5 +1,3 @@
import { InputAction } from "tiny-undo";
/**
* Define storage data type
*/
@ -9,14 +7,6 @@ interface StorageData {
shouldSplitMemoWord: boolean;
shouldHideImageUrl: boolean;
shouldUseMarkdownParser: boolean;
// Editor setting
useTinyUndoHistoryCache: boolean;
// tiny undo actions cache
tinyUndoActionsCache: InputAction[];
// tiny undo index cache
tinyUndoIndexCache: number;
}
type StorageKey = keyof StorageData;

View File

@ -2,18 +2,10 @@
.common-editor-wrapper {
.flex(column, flex-start, flex-start);
position: relative;
width: 100%;
height: auto;
background-color: white;
@apply relative w-full h-full bg-white grow;
> .common-editor-inputer {
display: inline-block;
width: 100%;
padding-top: 4px;
padding-bottom: 12px;
min-height: 40px;
max-height: 300px;
@apply w-full h-full pt-1 pb-3 grow;
font-size: 15px;
line-height: 24px;
resize: none;
@ -22,7 +14,6 @@
background-color: transparent;
z-index: 1;
white-space: pre-wrap;
.hide-scroll-bar();
&::placeholder {
padding-left: 2px;

View File

@ -8,7 +8,7 @@
body,
html {
@apply w-full h-full overflow-hidden text-base;
@apply w-screen h-screen overflow-hidden text-base;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans", "Noto Sans CJK SC", "Microsoft YaHei UI", "Microsoft YaHei",
"WenQuanYi Micro Hei", sans-serif, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";

View File

@ -6,10 +6,5 @@
#page-wrapper {
.flex(row, flex-start, flex-start);
@apply w-full max-w-4xl h-full m-auto -translate-x-4;
> .content-wrapper {
.flex(column, flex-start, flex-start);
@apply relative flex-grow h-auto;
}
@apply w-full h-full m-auto;
}

View File

@ -1,14 +1,7 @@
@import "./mixin.less";
.memo-editor-wrapper {
.flex(column, flex-start, flex-start);
position: relative;
width: 100%;
height: auto;
background-color: white;
padding: 16px;
border-radius: 8px;
border: 2px solid @bg-gray;
.memo-editor-container {
@apply relative w-full h-96 max-h-full flex flex-col justify-start items-start grow bg-white p-4 rounded-lg border-2 border-gray-200;
&.edit-ing {
border-color: @text-blue;

View File

@ -2,34 +2,18 @@
.filter-query-container {
.flex(row, flex-start, flex-start);
width: 100%;
flex-wrap: wrap;
padding: 12px 12px;
padding-bottom: 4px;
font-size: 13px;
line-height: 1.8;
@apply w-full flex-wrap p-3 pb-1 text-sm leading-7;
> .tip-text {
padding: 2px 0;
@apply mr-2;
}
> .filter-item-container {
padding: 2px 8px;
margin-right: 6px;
cursor: pointer;
background-color: @bg-gray;
border-radius: 4px;
@apply px-2 mr-2 cursor-pointer bg-gray-200 rounded whitespace-nowrap truncate hover:line-through;
max-width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
> .icon-text {
letter-spacing: 2px;
}
&:hover {
text-decoration: line-through;
}
}
}

View File

@ -1,6 +1,6 @@
@import "./mixin.less";
.memolist-wrapper {
.memo-list-container {
.flex(column, flex-start, flex-start);
flex-grow: 1;
width: 100%;

View File

@ -2,6 +2,7 @@
@import "./memos-header.less";
.memo-trash-wrapper {
@apply px-8;
.flex(column, flex-start, flex-start);
width: 100%;
height: 100%;

View File

@ -3,16 +3,7 @@
.memo-wrapper {
.flex(column, flex-start, flex-start);
width: 100%;
padding: 12px 18px;
background-color: white;
margin-top: 8px;
border-radius: 8px;
border: 1px solid transparent;
&:hover {
border-color: @bg-gray;
}
@apply w-full p-4 px-6 mt-2 bg-white rounded-lg border border-transparent hover:border-gray-200;
> .memo-top-wrapper {
.flex(row, space-between, center);
@ -21,10 +12,8 @@
margin-bottom: 4px;
> .time-text {
font-size: 12px;
line-height: 24px;
@apply text-xs;
color: gray;
flex-shrink: 0;
cursor: pointer;
}
@ -114,7 +103,7 @@
}
> .memo-content-text {
width: 100%;
@apply w-full;
}
> .images-wrapper {

15
web/src/less/memos.less Normal file
View File

@ -0,0 +1,15 @@
@import "./mixin.less";
@import "./memos-header.less";
.memos-wrapper {
.flex(row, flex-start, flex-start);
@apply w-auto h-full grow;
> .memo-editor-wrapper {
@apply w-96 h-full shrink-0 py-16 px-8 bg-white;
}
> .memo-list-wrapper {
@apply w-auto h-full grow px-16 flex flex-col justify-start items-start;
}
}

View File

@ -1,7 +1,7 @@
@import "./mixin.less";
.search-bar-container {
width: 160px;
@apply relative w-40;
> .search-bar-inputer {
.flex(row, flex-start, center);
@ -30,13 +30,8 @@
}
> .quickly-action-wrapper {
display: none;
position: absolute;
top: 52px;
right: -8px;
@apply hidden absolute top-9 -right-2 p-2 w-80;
z-index: 2;
padding: 8px;
width: 320px;
> .quickly-action-container {
.flex(column, flex-start, flex-start);

View File

@ -3,7 +3,7 @@
.preference-wrapper {
.flex(column, flex-start, flex-start);
@apply w-full h-full grow overflow-y-scroll;
@apply w-full h-full grow overflow-y-scroll px-8;
.hide-scroll-bar();
> .section-header-container {

View File

@ -2,7 +2,7 @@
.sidebar-wrapper {
.flex(column, flex-start, flex-start);
@apply w-60 h-auto py-4 overflow-x-hidden overflow-y-auto shrink-0;
@apply w-60 h-full py-4 overflow-x-hidden overflow-y-auto shrink-0;
.hide-scroll-bar();
> * {

View File

@ -37,7 +37,7 @@ function Home() {
{loadingState.isLoading ? null : (
<section id="page-wrapper">
<Sidebar />
<main className="content-wrapper">{homeRouterSwitch(pathname)}</main>
{homeRouterSwitch(pathname)}
</section>
)}
</>

View File

@ -2,15 +2,20 @@ import MemoEditor from "../components/MemoEditor";
import MemosHeader from "../components/MemosHeader";
import MemoFilter from "../components/MemoFilter";
import MemoList from "../components/MemoList";
import "../less/memos.less";
function Memos() {
return (
<>
<MemosHeader />
<MemoEditor />
<MemoFilter />
<MemoList />
</>
<main className="memos-wrapper">
<div className="memo-editor-wrapper">
<MemoEditor />
</div>
<div className="memo-list-wrapper">
<MemosHeader />
<MemoFilter />
<MemoList />
</div>
</main>
);
}

View File

@ -12,7 +12,7 @@ import "../less/memo-trash.less";
interface Props {}
const MemoTrash: React.FC<Props> = () => {
const Trash: React.FC<Props> = () => {
const {
locationState: { query },
} = useContext(appContext);
@ -126,4 +126,4 @@ const MemoTrash: React.FC<Props> = () => {
);
};
export default MemoTrash;
export default Trash;

View File

@ -1,9 +1,9 @@
import Memos from "../pages/Memos";
import MemoTrash from "../pages/MemoTrash";
import Trash from "../pages/Trash";
import Setting from "../pages/Setting";
const homeRouter = {
"/recycle": <MemoTrash />,
"/trash": <Trash />,
"/setting": <Setting />,
"*": <Memos />,
};

View File

@ -4,12 +4,11 @@ import { AppSetting } from "../stores/globalStateStore";
class GlobalStateService {
constructor() {
const cachedSetting = storage.get(["shouldSplitMemoWord", "shouldHideImageUrl", "shouldUseMarkdownParser", "useTinyUndoHistoryCache"]);
const cachedSetting = storage.get(["shouldSplitMemoWord", "shouldHideImageUrl", "shouldUseMarkdownParser"]);
const defaultAppSetting = {
shouldSplitMemoWord: cachedSetting.shouldSplitMemoWord ?? true,
shouldHideImageUrl: cachedSetting.shouldHideImageUrl ?? true,
shouldUseMarkdownParser: cachedSetting.shouldUseMarkdownParser ?? true,
useTinyUndoHistoryCache: cachedSetting.useTinyUndoHistoryCache ?? false,
};
this.setAppSetting(defaultAppSetting);

View File

@ -185,7 +185,7 @@ class LocationService {
};
public getValidPathname = (pathname: string): AppRouter => {
if (["/", "/signin", "/recycle", "/setting"].includes(pathname)) {
if (["/", "/signin", "/trash", "/setting"].includes(pathname)) {
return pathname as AppRouter;
} else {
return "/";

View File

@ -82,6 +82,7 @@ class ShortcutService {
public convertResponseModelShortcut(shortcut: Model.Shortcut): Model.Shortcut {
return {
...shortcut,
id: String(shortcut.id),
createdAt: utils.getDataStringWithTs(shortcut.createdTs),
updatedAt: utils.getDataStringWithTs(shortcut.updatedTs),
};

View File

@ -2,7 +2,6 @@ export interface AppSetting {
shouldSplitMemoWord: boolean;
shouldHideImageUrl: boolean;
shouldUseMarkdownParser: boolean;
useTinyUndoHistoryCache: boolean;
}
export interface State extends AppSetting {
@ -71,5 +70,4 @@ export const defaultState: State = {
shouldSplitMemoWord: true,
shouldHideImageUrl: true,
shouldUseMarkdownParser: true,
useTinyUndoHistoryCache: false,
};

View File

@ -165,7 +165,7 @@ export function reducer(state: State, action: Actions) {
...state,
query: {
...state.query,
filter: action.payload,
shortcutId: action.payload,
},
};
}

View File

@ -11,7 +11,7 @@ interface Query {
shortcutId: string;
}
type AppRouter = "/" | "/signin" | "/recycle" | "/setting";
type AppRouter = "/" | "/signin" | "/trash" | "/setting";
interface AppLocation {
pathname: AppRouter;

View File

@ -2294,11 +2294,6 @@ text-table@^0.2.0:
resolved "https://registry.nlark.com/text-table/download/text-table-0.2.0.tgz?cache=0&sync_timestamp=1618846790938&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftext-table%2Fdownload%2Ftext-table-0.2.0.tgz"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
tiny-undo@^0.0.8:
version "0.0.8"
resolved "https://registry.npmjs.org/tiny-undo/-/tiny-undo-0.0.8.tgz"
integrity sha512-x/zUWVVoehq0TTLTLngUCvg41bssl5OYloNOE6sRz/2fsEetB87zpj4kEZyrmvzI3Rsq+t9olujqXprlu+lbvw==
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"