未验证 提交 cd7000da 编写于 作者: S STEVEN 提交者: GitHub

feat: responsive view (#75)

* chore: add license

* feat: mobile view
上级 b96d78ed
MIT License
Copyright (c) 2022 Memos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
......@@ -33,6 +33,5 @@
"tailwindcss": "^3.0.18",
"typescript": "^4.3.2",
"vite": "^2.9.0"
},
"license": "MIT"
}
}
......@@ -150,11 +150,11 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
{linkMemos.length > 0 ? (
<div className="linked-memos-wrapper">
<p className="normal-text">{linkMemos.length} related MEMO</p>
{linkMemos.map((m) => {
const rawtext = parseHtmlToRawText(formatMemoContent(m.content)).replaceAll("\n", " ");
{linkMemos.map((memo, index) => {
const rawtext = parseHtmlToRawText(formatMemoContent(memo.content)).replaceAll("\n", " ");
return (
<div className="linked-memo-container" key={m.id} onClick={() => handleLinkedMemoClick(m)}>
<span className="time-text">{m.dateStr} </span>
<div className="linked-memo-container" key={`${index}-${memo.id}`} onClick={() => handleLinkedMemoClick(memo)}>
<span className="time-text">{memo.dateStr} </span>
{rawtext}
</div>
);
......@@ -164,11 +164,11 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
{linkedMemos.length > 0 ? (
<div className="linked-memos-wrapper">
<p className="normal-text">{linkedMemos.length} linked MEMO</p>
{linkedMemos.map((m) => {
const rawtext = parseHtmlToRawText(formatMemoContent(m.content)).replaceAll("\n", " ");
{linkedMemos.map((memo, index) => {
const rawtext = parseHtmlToRawText(formatMemoContent(memo.content)).replaceAll("\n", " ");
return (
<div className="linked-memo-container" key={m.id} onClick={() => handleLinkedMemoClick(m)}>
<span className="time-text">{m.dateStr} </span>
<div className="linked-memo-container" key={`${index}-${memo.id}`} onClick={() => handleLinkedMemoClick(memo)}>
<span className="time-text">{memo.dateStr} </span>
{rawtext}
</div>
);
......
......@@ -294,7 +294,7 @@ const MemoEditor: React.FC<Props> = () => {
/>
<div
ref={tagSeletorRef}
className={`tag-list ${isTagSeletorShown && tags.length > 0 ? "" : "hidden"}`}
className={`tag-list ${isTagSeletorShown && tags.length > 0 ? "" : "!hidden"}`}
onClick={handleTagSeletorClick}
>
{tags.map((t) => {
......
import { useCallback, useEffect, useState } from "react";
import { memoService, shortcutService } from "../services";
import { useAppSelector } from "../store";
import SearchBar from "./SearchBar";
import { memoService, shortcutService } from "../services";
import { toggleSiderbar } from "./Sidebar";
import "../less/memos-header.less";
let prevRequestTimestamp = Date.now();
......@@ -25,7 +26,7 @@ const MemosHeader: React.FC<Props> = () => {
}
}, [query, shortcuts]);
const handleMemoTextClick = useCallback(() => {
const handleTitleTextClick = useCallback(() => {
const now = Date.now();
if (now - prevRequestTimestamp > 10 * 1000) {
prevRequestTimestamp = now;
......@@ -37,8 +38,13 @@ const MemosHeader: React.FC<Props> = () => {
return (
<div className="section-header-container memos-header-container">
<div className="title-text" onClick={handleMemoTextClick}>
<span className="normal-text">{titleText}</span>
<div className="title-container">
<div className="action-btn" onClick={toggleSiderbar}>
<img src="/icons/menu.svg" className="icon-img" alt="" />
</div>
<span className="title-text" onClick={handleTitleTextClick}>
{titleText}
</span>
</div>
<SearchBar />
</div>
......
......@@ -34,27 +34,31 @@ const SettingDialog: React.FC<Props> = (props: Props) => {
</button>
<div className="section-selector-container">
<span className="section-title">Basic</span>
<span
onClick={() => handleSectionSelectorItemClick("my-account")}
className={`section-item ${state.selectedSection === "my-account" ? "selected" : ""}`}
>
My account
</span>
<span
onClick={() => handleSectionSelectorItemClick("preferences")}
className={`section-item ${state.selectedSection === "preferences" ? "selected" : ""}`}
>
Preferences
</span>
<div className="section-items-container">
<span
onClick={() => handleSectionSelectorItemClick("my-account")}
className={`section-item ${state.selectedSection === "my-account" ? "selected" : ""}`}
>
My account
</span>
<span
onClick={() => handleSectionSelectorItemClick("preferences")}
className={`section-item ${state.selectedSection === "preferences" ? "selected" : ""}`}
>
Preferences
</span>
</div>
{user?.role === "OWNER" ? (
<>
<span className="section-title">Admin</span>
<span
onClick={() => handleSectionSelectorItemClick("member")}
className={`section-item ${state.selectedSection === "member" ? "selected" : ""}`}
>
Member
</span>
<div className="section-items-container">
<span
onClick={() => handleSectionSelectorItemClick("member")}
className={`section-item ${state.selectedSection === "member" ? "selected" : ""}`}
>
Member
</span>
</div>
</>
) : null}
</div>
......
......@@ -27,6 +27,11 @@ const Sidebar: React.FC<Props> = () => {
return (
<aside className="sidebar-wrapper">
<div className="close-container">
<span className="action-btn" onClick={toggleSiderbar}>
<img src="/icons/close.svg" className="icon-img" alt="" />
</span>
</div>
<UserBanner />
<div className="status-text-container">
<div className="status-text memos-text">
......@@ -57,4 +62,14 @@ const Sidebar: React.FC<Props> = () => {
);
};
export const toggleSiderbar = () => {
const sidebarEl = document.body.querySelector(".sidebar-wrapper") as HTMLDivElement;
const display = window.getComputedStyle(sidebarEl).display;
if (display === "none") {
sidebarEl.style.display = "flex";
} else {
sidebarEl.style.display = "none";
}
};
export default Sidebar;
import axios from "axios";
axios.defaults.withCredentials = true;
type ResponseObject<T> = {
data: T;
error?: string;
......
@import "./mixin.less";
#root {
.flex(row, flex-start, flex-start);
@apply w-full h-full;
}
@import "./mixin.less";
* {
@apply m-0 p-0 box-border;
color: @text-black;
-webkit-tap-highlight-color: transparent;
}
body,
html {
@apply w-screen h-screen overflow-hidden text-base;
@apply 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";
}
code {
@apply bg-pink-600 p-1 rounded font-mono;
}
pre {
@apply font-mono;
* {
@apply font-mono;
}
}
label,
button,
img {
......@@ -57,17 +39,10 @@ li {
}
a {
@apply cursor-pointer text-blue-600 underline underline-offset-2;
&:hover {
@apply opacity-80;
}
@apply cursor-pointer text-blue-600 underline underline-offset-2 hover:opacity-80;
}
.btn {
@apply select-none cursor-pointer text-center;
}
.hidden {
display: none !important;
}
@import "./mixin.less";
@import "./memos-header.less";
#root {
.page-wrapper.home {
@apply relative top-0 w-full h-screen overflow-y-auto;
background-color: #f6f5f4;
}
#page-wrapper {
@apply w-full h-full m-auto grid max-w-4xl mx-auto;
grid-template-columns: min-content 1fr;
> .page-container {
@apply relative w-full min-h-screen mx-auto flex flex-row justify-center items-start;
>.sidebar-wrapper{
@apply flex-shrink-0;
}
> .memos-wrapper {
@apply relative w-full max-w-2xl min-h-full overflow-x-hidden flex flex-col justify-start items-start px-4 sm:pr-6;
.memos-wrapper {
@apply w-full h-full overflow-x-hidden flex flex-col justify-start items-start px-4 pr-10;
}
}
}
@import "./mixin.less";
.dialog-wrapper.memo-card-dialog {
> .dialog-container {
@apply p-0 bg-transparent;
@apply px-4;
> * {
@apply shrink-0;
}
> .dialog-container {
@apply w-full p-0 bg-transparent flex flex-col justify-start items-center;
> .memo-card-container {
.flex(column, flex-start, flex-start);
......
@import "./mixin.less";
@import "./memos-header.less";
.memo-trash-dialog {
@apply px-4;
> .dialog-container {
@apply w-128 max-w-full mb-8;
......
......@@ -5,20 +5,22 @@
.flex(row, space-between, center);
@apply w-full h-10 flex-nowrap mt-4 mb-2 shrink-0;
> .title-text {
.flex(row, flex-start, center);
@apply font-bold text-lg leading-10 mr-2 text-ellipsis shrink-0 cursor-pointer overflow-hidden;
color: @text-black;
> .title-container {
@apply flex flex-row justify-start items-center mr-2 shrink-0 overflow-hidden;
> .action-btn {
.flex(row, center, center);
@apply w-6 h-6 mr-1 shrink-0;
@apply flex sm:hidden flex-row justify-center items-center w-6 h-6 mr-1 shrink-0;
background-color: unset;
> .icon-img {
@apply w-4 h-auto;
@apply w-5 h-auto;
}
}
> .title-text {
@apply font-bold text-lg leading-10 mr-2 text-ellipsis shrink-0 cursor-pointer overflow-hidden;
color: @text-black;
}
}
> .btns-container {
......
......@@ -2,22 +2,14 @@
.menu-btns-popup {
.flex(column, flex-start, flex-start);
@apply absolute mt-1 ml-24 p-1 w-44 rounded-lg z-10 shadow bg-white;
&:hover {
display: flex;
}
@apply absolute right-0 top-0 mt-1 p-1 w-36 rounded-lg z-10 shadow bg-white;
> .btn {
.flex(row, flex-start, center);
@apply w-full py-2 px-3 text-base rounded text-left;
@apply w-full py-2 px-3 text-base rounded text-left hover:bg-gray-100;
> .icon {
@apply block w-6 text-center mr-2 text-base;
}
&:hover {
background-color: @bg-whitegray;
}
}
}
......@@ -15,10 +15,6 @@
@bg-light-blue: #eef3fe;
@bg-paper-yellow: #fbf4de;
.mono-font-family {
font-family: SFMono-Regular, Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace;
}
.hide-scroll-bar {
.pretty-scroll-bar(0, 0);
......
......@@ -23,8 +23,7 @@
}
> .quickly-action-wrapper {
@apply hidden absolute top-9 -right-2 p-2 w-80;
z-index: 2;
@apply hidden absolute top-9 -right-2 p-2 w-80 z-10;
> .quickly-action-container {
.flex(column, flex-start, flex-start);
......
@import "./mixin.less";
@import "./memos-header.less";
.setting-dialog {
@apply px-4;
> .dialog-container {
@apply w-176 max-w-full mb-8 p-0;
> .dialog-content-container {
.flex(column, flex-start, flex-start);
@apply relative w-full overflow-y-scroll p-0 flex flex-row justify-start items-start;
@apply relative w-full overflow-y-scroll p-0 flex flex-col sm:flex-row justify-start items-start;
.hide-scroll-bar();
> .close-btn {
......@@ -20,23 +21,28 @@
}
> .section-selector-container {
@apply w-40 h-full shrink-0 rounded-l-lg p-4 border-r bg-gray-100 flex flex-col justify-start items-start;
@apply w-full sm:w-40 h-auto sm:h-full shrink-0 rounded-t-lg sm:rounded-l-lg p-4 border-r bg-gray-100 flex flex-col justify-start items-start;
> .section-title {
@apply text-sm mt-4 first:mt-3 mb-1 font-mono text-gray-400;
}
> .section-item {
@apply text-base left-6 mt-2 text-gray-700 cursor-pointer hover:opacity-80;
>.section-items-container{
@apply w-full h-auto flex flex-row sm:flex-col justify-start items-start;
&.selected {
@apply font-bold hover:opacity-100;
> .section-item {
@apply text-base mr-2 sm:mr-0 mt-2 text-gray-700 cursor-pointer hover:opacity-80;
&.selected {
@apply font-bold hover:opacity-100;
}
}
}
}
> .section-content-container {
@apply w-auto p-4 px-6 grow flex flex-col justify-start items-start h-128 overflow-y-scroll;
@apply w-full sm:w-auto p-4 px-6 grow flex flex-col justify-start items-start h-128 overflow-y-scroll;
> .section-container {
.flex(column, flex-start, flex-start);
......@@ -47,8 +53,7 @@
}
> .form-label {
.flex(row, flex-start, center);
@apply w-full mb-2;
@apply flex flex-row justify-start items-center w-full mb-2;
> .normal-text {
@apply shrink-0 select-text;
......
......@@ -9,12 +9,14 @@
}
&.username-label {
@apply w-full flex-wrap;
> input {
@apply grow-0 shadow-inner w-auto px-2 py-1 text-base border rounded leading-6 bg-transparent focus:border-black;
@apply grow-0 shadow-inner w-auto px-2 py-1 mr-2 text-base border rounded leading-6 bg-transparent focus:border-black;
}
> .btns-container {
@apply ml-2 shrink-0 flex flex-row justify-start items-center;
@apply mr-2 shrink-0 flex flex-row justify-start items-center;
> .btn {
@apply text-sm shadow px-4 py-1 leading-6 rounded border hover:opacity-80 bg-gray-50;
......
@import "./mixin.less";
.sidebar-wrapper {
.flex(column, flex-start, flex-start);
@apply w-64 h-full py-4 pl-2 overflow-x-hidden overflow-y-auto;
@apply fixed sm:sticky top-0 left-0 hidden sm:!flex flex-col justify-start items-start w-64 h-screen py-4 pl-2 z-10 bg-white sm:bg-transparent shadow-2xl sm:shadow-none overflow-x-hidden overflow-y-auto transition-all;
.hide-scroll-bar();
> .close-container {
@apply w-full pr-6 my-2 flex sm:hidden flex-row justify-end items-center;
> .action-btn {
@apply p-1 bg-gray-100 rounded shadow;
> .icon-img {
@apply w-4 h-auto;
}
}
}
> .action-btns-container {
@apply w-full px-2 my-2 flex flex-col justify-start items-start shrink-0;
......
......@@ -2,7 +2,7 @@
.page-wrapper.signin {
.flex(row, center, center);
@apply w-full h-full bg-white;
@apply w-full min-h-screen bg-white;
> .page-container {
@apply w-80 max-w-full py-4 -mt-16;
......
......@@ -32,9 +32,9 @@ function Home() {
}, []);
return (
<>
<section className="page-wrapper home">
{loadingState.isLoading ? null : (
<section id="page-wrapper">
<div className="page-container">
<Sidebar />
<main className="memos-wrapper">
<MemosHeader />
......@@ -42,9 +42,9 @@ function Home() {
<MemoFilter />
<MemoList />
</main>
</section>
</div>
)}
</>
</section>
);
}
......
......@@ -16,5 +16,5 @@
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["./src", "./public"]
"include": ["./src"]
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册