fix(fe/files_panel): use table layout and fix issues
This commit is contained in:
parent
0fc878ea7b
commit
3133720d79
14 changed files with 262 additions and 133 deletions
|
@ -479,3 +479,18 @@
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-mid {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -91,13 +91,20 @@
|
||||||
.theme-default #breadcrumb .item {
|
.theme-default #breadcrumb .item {
|
||||||
color: #697384;
|
color: #697384;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
/* padding: 1rem; */
|
max-width: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default #breadcrumb .content {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-default #breadcrumb .item {
|
.theme-default #breadcrumb .item {
|
||||||
color: #697384;
|
color: #697384;
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
/* padding: 1rem; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
@ -136,23 +143,52 @@
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-default #icon-home {
|
.theme-default #item-table {
|
||||||
color: black;
|
width: 100%;
|
||||||
margin-right: 1rem;
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-default #browser .item-op {
|
.theme-default #item-table thead,
|
||||||
line-height: 4rem;
|
.theme-default #item-table tfoot,
|
||||||
padding: 1rem 0;
|
.theme-default #item-table tbody,
|
||||||
text-align: right;
|
.theme-default #item-table tr {
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.theme-default #item-table td,
|
||||||
|
.theme-default #item-table th {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default .item-cell {
|
||||||
|
height: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default .float-menu {
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 5px 30px 0 rgba(31, 38, 135, 0.1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-default #browser .item-info {
|
.theme-default #browser .item-info {
|
||||||
padding: 1rem;
|
padding: 1rem 0;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
border-top: dashed 1px #7f8c8d;
|
border-top: dashed 1px #7f8c8d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-default #browser .item-op {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default #icon-home {
|
||||||
|
color: black;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-default #browser .error {
|
.theme-default #browser .error {
|
||||||
line-height: 4rem;
|
line-height: 4rem;
|
||||||
border: dashed 1px #e74c3c;
|
border: dashed 1px #e74c3c;
|
||||||
|
|
|
@ -75,7 +75,7 @@ describe("Login", () => {
|
||||||
uploadSpeedLimit: 3,
|
uploadSpeedLimit: 3,
|
||||||
downloadSpeedLimit: 3,
|
downloadSpeedLimit: 3,
|
||||||
},
|
},
|
||||||
captchaID: "",
|
captchaID: "mockCaptchaID",
|
||||||
preferences: {
|
preferences: {
|
||||||
bg: {
|
bg: {
|
||||||
url: "bgUrl",
|
url: "bgUrl",
|
||||||
|
|
|
@ -75,7 +75,7 @@ describe("State Manager", () => {
|
||||||
downloadSpeedLimit: 3,
|
downloadSpeedLimit: 3,
|
||||||
},
|
},
|
||||||
authed: true,
|
authed: true,
|
||||||
captchaID: "",
|
captchaID: "mockCaptchaID",
|
||||||
preferences: {
|
preferences: {
|
||||||
bg: {
|
bg: {
|
||||||
url: "bgUrl",
|
url: "bgUrl",
|
||||||
|
@ -185,7 +185,7 @@ describe("State Manager", () => {
|
||||||
quota: mockSelfResp.data.quota,
|
quota: mockSelfResp.data.quota,
|
||||||
usedSpace: mockSelfResp.data.usedSpace,
|
usedSpace: mockSelfResp.data.usedSpace,
|
||||||
authed: false,
|
authed: false,
|
||||||
captchaID: "",
|
captchaID: "mockCaptchaID",
|
||||||
preferences: {
|
preferences: {
|
||||||
bg: {
|
bg: {
|
||||||
url: "",
|
url: "",
|
||||||
|
|
|
@ -79,6 +79,7 @@ describe("TopBar", () => {
|
||||||
updater().setClients(usersCl, filesCl, settingsCl);
|
updater().setClients(usersCl, filesCl, settingsCl);
|
||||||
|
|
||||||
const topbar = new TopBar({
|
const topbar = new TopBar({
|
||||||
|
ui: coreState.ui,
|
||||||
login: coreState.login,
|
login: coreState.login,
|
||||||
msg: coreState.msg,
|
msg: coreState.msg,
|
||||||
update: (updater: (prevState: ICoreState) => ICoreState) => {},
|
update: (updater: (prevState: ICoreState) => ICoreState) => {},
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
children: List<JSX.Element>;
|
children: List<React.ReactNode>;
|
||||||
childrenStyles?: List<React.CSSProperties>;
|
childrenStyles?: List<React.CSSProperties>;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -25,7 +25,7 @@ const childrenStyle = {
|
||||||
export const Flexbox = (props: Props) => {
|
export const Flexbox = (props: Props) => {
|
||||||
const childrenCount = props.children.size;
|
const childrenCount = props.children.size;
|
||||||
const children = props.children.map(
|
const children = props.children.map(
|
||||||
(child: JSX.Element, i: number): JSX.Element => {
|
(child: React.ReactNode, i: number): React.ReactNode => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`fb-${i}`}
|
key={`fb-${i}`}
|
||||||
|
|
|
@ -2,14 +2,14 @@ import * as React from "react";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
grids: List<JSX.Element>;
|
grids: List<React.ReactNode>;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Flowgrid = (props: Props) => {
|
export const Flowgrid = (props: Props) => {
|
||||||
const children = props.grids.map(
|
const children = props.grids.map(
|
||||||
(child: JSX.Element, i: number): JSX.Element => {
|
(child: React.ReactNode, i: number): React.ReactNode => {
|
||||||
return (
|
return (
|
||||||
<span key={`flowgrid-${i}`} className="inline-block">
|
<span key={`flowgrid-${i}`} className="inline-block">
|
||||||
{child}
|
{child}
|
||||||
|
|
60
src/client/web/src/components/layout/table.tsx
Normal file
60
src/client/web/src/components/layout/table.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { List } from "immutable";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
head: List<React.ReactNode>;
|
||||||
|
rows: List<List<React.ReactNode>>;
|
||||||
|
foot: List<React.ReactNode>;
|
||||||
|
colStyles?: List<React.CSSProperties>;
|
||||||
|
id?: string;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Table = (props: Props) => {
|
||||||
|
const headCols = props.head.map(
|
||||||
|
(elem: React.ReactNode, i: number): React.ReactNode => {
|
||||||
|
const style = props.colStyles != null ? props.colStyles.get(i) : {};
|
||||||
|
return (
|
||||||
|
<th key={`h-${i}`} style={style}>
|
||||||
|
{elem}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const bodyRows = props.rows.map(
|
||||||
|
(row: List<React.ReactNode>, i: number): React.ReactNode => {
|
||||||
|
const tds = row.map((elem: React.ReactNode, j: number) => {
|
||||||
|
const style = props.colStyles != null ? props.colStyles.get(j) : {};
|
||||||
|
return (
|
||||||
|
<td key={`rc-${i}-${j}`} style={style}>
|
||||||
|
{elem}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return <tr key={`r-${i}`}>{tds}</tr>;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const footCols = props.foot.map(
|
||||||
|
(elem: React.ReactNode, i: number): React.ReactNode => {
|
||||||
|
const style = props.colStyles != null ? props.colStyles.get(i) : {};
|
||||||
|
return (
|
||||||
|
<th key={`f-${i}`} style={style}>
|
||||||
|
{elem}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table id={props.id} style={props.style} className={props.className}>
|
||||||
|
<thead>
|
||||||
|
<tr>{headCols}</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>{bodyRows}</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>{footCols}</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
};
|
|
@ -63,13 +63,13 @@ export class AuthPane extends React.Component<Props, State, {}> {
|
||||||
this.state.captchaInput
|
this.state.captchaInput
|
||||||
)
|
)
|
||||||
.then((ok: boolean): Promise<any> => {
|
.then((ok: boolean): Promise<any> => {
|
||||||
|
this.setState({ captchaInput: "" });
|
||||||
if (ok) {
|
if (ok) {
|
||||||
const params = new URLSearchParams(
|
const params = new URLSearchParams(
|
||||||
document.location.search.substring(1)
|
document.location.search.substring(1)
|
||||||
);
|
);
|
||||||
return updater().initAll(params);
|
return updater().initAll(params);
|
||||||
} else {
|
} else {
|
||||||
this.setState({ user: "", pwd: "", captchaInput: "" });
|
|
||||||
alertMsg(this.props.msg.pkg.get("op.fail"));
|
alertMsg(this.props.msg.pkg.get("op.fail"));
|
||||||
return updater().getCaptchaID();
|
return updater().getCaptchaID();
|
||||||
}
|
}
|
||||||
|
@ -145,10 +145,7 @@ export class AuthPane extends React.Component<Props, State, {}> {
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className="float-input">
|
<span className="float-input">
|
||||||
<button
|
<button id="btn-login" onClick={this.login}>
|
||||||
id="btn-login"
|
|
||||||
onClick={this.login}
|
|
||||||
>
|
|
||||||
{this.props.msg.pkg.get("login.login")}
|
{this.props.msg.pkg.get("login.login")}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -4,8 +4,9 @@ import { List, Map, Set } from "immutable";
|
||||||
import FileSize from "filesize";
|
import FileSize from "filesize";
|
||||||
|
|
||||||
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
||||||
import { RiHomeSmileFill } from "@react-icons/all-files/ri/RiHomeSmileFill";
|
import { RiArchiveDrawerFill } from "@react-icons/all-files/ri/RiArchiveDrawerFill";
|
||||||
import { RiFile2Fill } from "@react-icons/all-files/ri/RiFile2Fill";
|
import { RiFile2Fill } from "@react-icons/all-files/ri/RiFile2Fill";
|
||||||
|
import { RiFileList2Fill } from "@react-icons/all-files/ri/RiFileList2Fill";
|
||||||
|
|
||||||
import { alertMsg, confirmMsg } from "../common/env";
|
import { alertMsg, confirmMsg } from "../common/env";
|
||||||
import { updater } from "./state_updater";
|
import { updater } from "./state_updater";
|
||||||
|
@ -14,6 +15,7 @@ import { LoginProps } from "./pane_login";
|
||||||
import { MetadataResp, roleVisitor, roleAdmin } from "../client";
|
import { MetadataResp, roleVisitor, roleAdmin } from "../client";
|
||||||
import { Flexbox } from "./layout/flexbox";
|
import { Flexbox } from "./layout/flexbox";
|
||||||
import { Container } from "./layout/container";
|
import { Container } from "./layout/container";
|
||||||
|
import { Table } from "./layout/table";
|
||||||
import { Up } from "../worker/upload_mgr";
|
import { Up } from "../worker/upload_mgr";
|
||||||
import { UploadEntry, UploadState } from "../worker/interface";
|
import { UploadEntry, UploadState } from "../worker/interface";
|
||||||
import { getIcon } from "./visual/icons";
|
import { getIcon } from "./visual/icons";
|
||||||
|
@ -222,6 +224,14 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
return this.chdir(this.props.filesInfo.dirPath.push(childDirName));
|
return this.chdir(this.props.filesInfo.dirPath.push(childDirName));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
goHome = async () => {
|
||||||
|
return updater()
|
||||||
|
.setHomeItems()
|
||||||
|
.then(() => {
|
||||||
|
this.props.update(updater().updateFilesInfo);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
chdir = async (dirPath: List<string>) => {
|
chdir = async (dirPath: List<string>) => {
|
||||||
if (dirPath === this.props.filesInfo.dirPath) {
|
if (dirPath === this.props.filesInfo.dirPath) {
|
||||||
return;
|
return;
|
||||||
|
@ -330,16 +340,12 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
}
|
}
|
||||||
className="item"
|
className="item"
|
||||||
>
|
>
|
||||||
{pathPart}
|
<span className="content">{pathPart}</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const nameWidthClass = `item-name item-name-${
|
|
||||||
this.props.ui.isVertical ? "vertical" : "horizontal"
|
|
||||||
} pointer`;
|
|
||||||
|
|
||||||
const ops = (
|
const ops = (
|
||||||
<div id="upload-op">
|
<div id="upload-op">
|
||||||
<div className="float">
|
<div className="float">
|
||||||
|
@ -382,111 +388,52 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const itemList = sortedItems.map((item: MetadataResp) => {
|
const items = sortedItems.map((item: MetadataResp) => {
|
||||||
const isSelected = this.state.selectedItems.has(item.name);
|
const isSelected = this.state.selectedItems.has(item.name);
|
||||||
const dirPath = this.props.filesInfo.dirPath.join("/");
|
const dirPath = this.props.filesInfo.dirPath.join("/");
|
||||||
const itemPath = dirPath.endsWith("/")
|
const itemPath = dirPath.endsWith("/")
|
||||||
? `${dirPath}${item.name}`
|
? `${dirPath}${item.name}`
|
||||||
: `${dirPath}/${item.name}`;
|
: `${dirPath}/${item.name}`;
|
||||||
|
|
||||||
return item.isDir ? (
|
const icon = item.isDir ? (
|
||||||
<Flexbox
|
<div className="v-mid item-cell">
|
||||||
key={item.name}
|
<RiFolder2Fill size="3rem" className="yellow0-font" />
|
||||||
children={List([
|
</div>
|
||||||
<Flexbox
|
|
||||||
children={List([
|
|
||||||
<RiFolder2Fill
|
|
||||||
size="3rem"
|
|
||||||
className="yellow0-font margin-r-m"
|
|
||||||
/>,
|
|
||||||
|
|
||||||
<span className={`${nameWidthClass}`}>
|
|
||||||
<span
|
|
||||||
className="title-m"
|
|
||||||
onClick={() => this.gotoChild(item.name)}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</span>
|
|
||||||
<div className="desc-m grey0-font">
|
|
||||||
<span>
|
|
||||||
{item.modTime.slice(0, item.modTime.indexOf("T"))}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</span>,
|
|
||||||
])}
|
|
||||||
childrenStyles={List([
|
|
||||||
{ flex: "0 0 auto" },
|
|
||||||
{ flex: "0 0 auto" },
|
|
||||||
])}
|
|
||||||
/>,
|
|
||||||
<span className={`item-op ${showOp}`}>
|
|
||||||
<span onClick={() => this.select(item.name)} className="float-l">
|
|
||||||
{isSelected
|
|
||||||
? getIcon("RiCheckboxFill", "1.8rem", "cyan0")
|
|
||||||
: getIcon("RiCheckboxBlankFill", "1.8rem", "grey1")}
|
|
||||||
</span>
|
|
||||||
</span>,
|
|
||||||
])}
|
|
||||||
childrenStyles={List([
|
|
||||||
{ flex: "0 0 auto", width: "60%" },
|
|
||||||
{ flex: "0 0 auto", justifyContent: "flex-end", width: "40%" },
|
|
||||||
])}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<div key={item.name}>
|
<div className="v-mid item-cell">
|
||||||
<Flexbox
|
<RiFile2Fill size="3rem" className="cyan0-font" />
|
||||||
key={item.name}
|
</div>
|
||||||
children={List([
|
);
|
||||||
<Flexbox
|
|
||||||
children={List([
|
|
||||||
<RiFile2Fill size="3rem" className="cyan0-font margin-r-m" />,
|
|
||||||
|
|
||||||
<span className={`${nameWidthClass}`}>
|
const content = item.isDir ? (
|
||||||
<a
|
<div className={`v-mid item-cell`}>
|
||||||
className="title-m"
|
<div className="full-width">
|
||||||
href={`/v1/fs/files?fp=${itemPath}`}
|
<div className="title-m clickable" onClick={() => this.gotoChild(item.name)}>
|
||||||
target="_blank"
|
{item.name}
|
||||||
>
|
</div>
|
||||||
{item.name}
|
<div className="desc-m grey0-font">
|
||||||
</a>
|
<span>{item.modTime.slice(0, item.modTime.indexOf("T"))}</span>
|
||||||
<div className="desc-m grey0-font">
|
</div>
|
||||||
<span>
|
</div>
|
||||||
{item.modTime.slice(0, item.modTime.indexOf("T"))}
|
</div>
|
||||||
</span>
|
) : (
|
||||||
/
|
<div>
|
||||||
<span>{FileSize(item.size, { round: 0 })}</span>
|
<div className={`v-mid item-cell`}>
|
||||||
</div>
|
<div className="full-width">
|
||||||
</span>,
|
<a
|
||||||
])}
|
className="title-m clickable"
|
||||||
childrenStyles={List([
|
href={`/v1/fs/files?fp=${itemPath}`}
|
||||||
{ flex: "0 0 auto" },
|
target="_blank"
|
||||||
{ flex: "0 0 auto" },
|
>
|
||||||
])}
|
{item.name}
|
||||||
/>,
|
</a>
|
||||||
|
<div className="desc-m grey0-font">
|
||||||
<span className={`item-op ${showOp}`}>
|
<span>{item.modTime.slice(0, item.modTime.indexOf("T"))}</span>
|
||||||
<span
|
/
|
||||||
onClick={() => this.toggleDetail(item.name)}
|
<span>{FileSize(item.size, { round: 0 })}</span>
|
||||||
className="float-l"
|
</div>
|
||||||
>
|
</div>
|
||||||
{getIcon("RiInformationFill", "1.8rem", "grey1")}
|
</div>
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
onClick={() => this.select(item.name)}
|
|
||||||
className="float-l"
|
|
||||||
>
|
|
||||||
{isSelected
|
|
||||||
? getIcon("RiCheckboxFill", "1.8rem", "cyan0")
|
|
||||||
: getIcon("RiCheckboxBlankFill", "1.8rem", "grey1")}
|
|
||||||
</span>
|
|
||||||
</span>,
|
|
||||||
])}
|
|
||||||
childrenStyles={List([
|
|
||||||
{ flex: "0 0 auto", width: "60%" },
|
|
||||||
{ flex: "0 0 auto", justifyContent: "flex-end", width: "40%" },
|
|
||||||
])}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
|
@ -509,6 +456,33 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const op = item.isDir ? (
|
||||||
|
<div className={`v-mid item-cell item-op ${showOp}`}>
|
||||||
|
<span onClick={() => this.select(item.name)} className="float-l">
|
||||||
|
{isSelected
|
||||||
|
? getIcon("RiCheckboxFill", "1.8rem", "cyan0")
|
||||||
|
: getIcon("RiCheckboxBlankFill", "1.8rem", "grey1")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={`v-mid item-cell item-op ${showOp}`}>
|
||||||
|
<span
|
||||||
|
onClick={() => this.toggleDetail(item.name)}
|
||||||
|
className="float-l"
|
||||||
|
>
|
||||||
|
{getIcon("RiInformationFill", "1.8rem", "grey1")}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span onClick={() => this.select(item.name)} className="float-l">
|
||||||
|
{isSelected
|
||||||
|
? getIcon("RiCheckboxFill", "1.8rem", "cyan0")
|
||||||
|
: getIcon("RiCheckboxBlankFill", "1.8rem", "grey1")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return List([icon, content, op]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const usedSpace = FileSize(parseInt(this.props.login.usedSpace, 10), {
|
const usedSpace = FileSize(parseInt(this.props.login.usedSpace, 10), {
|
||||||
|
@ -521,8 +495,16 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const tableTitles = List([
|
||||||
|
<div className="font-s grey0-font">
|
||||||
|
<RiFileList2Fill size="3rem" className="black-font" />
|
||||||
|
</div>,
|
||||||
|
<div className="font-s grey0-font">Name</div>,
|
||||||
|
<div className="font-s grey0-font">Action</div>,
|
||||||
|
]);
|
||||||
|
|
||||||
const itemListPane = (
|
const itemListPane = (
|
||||||
<div id="item-list">
|
<div>
|
||||||
<div className={showOp}>
|
<div className={showOp}>
|
||||||
<Container>{ops}</Container>
|
<Container>{ops}</Container>
|
||||||
</div>
|
</div>
|
||||||
|
@ -595,7 +577,12 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
<span id="breadcrumb">
|
<span id="breadcrumb">
|
||||||
<Flexbox
|
<Flexbox
|
||||||
children={List([
|
children={List([
|
||||||
<RiHomeSmileFill size="3rem" id="icon-home" />,
|
<RiArchiveDrawerFill
|
||||||
|
size="3rem"
|
||||||
|
id="icon-home"
|
||||||
|
className="clickable"
|
||||||
|
onClick={this.goHome}
|
||||||
|
/>,
|
||||||
<Flexbox children={breadcrumb} />,
|
<Flexbox children={breadcrumb} />,
|
||||||
])}
|
])}
|
||||||
childrenStyles={List([
|
childrenStyles={List([
|
||||||
|
@ -614,7 +601,17 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{itemList}
|
<Table
|
||||||
|
colStyles={List([
|
||||||
|
{ width: "3rem", paddingRight: "1rem" },
|
||||||
|
{ width: "calc(100% - 12rem)", textAlign: "left" },
|
||||||
|
{ width: "8rem", textAlign: "right" },
|
||||||
|
])}
|
||||||
|
id="item-table"
|
||||||
|
head={tableTitles}
|
||||||
|
foot={List()}
|
||||||
|
rows={items}
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -77,6 +77,7 @@ export class RootFrame extends React.Component<Props, State, {}> {
|
||||||
<TopBar
|
<TopBar
|
||||||
login={this.props.login}
|
login={this.props.login}
|
||||||
msg={this.props.msg}
|
msg={this.props.msg}
|
||||||
|
ui={this.props.ui}
|
||||||
update={this.props.update}
|
update={this.props.update}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -417,6 +417,9 @@ export class Updater {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return this.syncCwd();
|
return this.syncCwd();
|
||||||
})
|
})
|
||||||
|
.then(() => {
|
||||||
|
return this.getCaptchaID();
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (this.props.login.userRole === roleAdmin) {
|
if (this.props.login.userRole === roleAdmin) {
|
||||||
return this.initStateForAdmin();
|
return this.initStateForAdmin();
|
||||||
|
|
|
@ -2,16 +2,23 @@ import * as React from "react";
|
||||||
import { List } from "immutable";
|
import { List } from "immutable";
|
||||||
import { alertMsg, confirmMsg } from "../common/env";
|
import { alertMsg, confirmMsg } from "../common/env";
|
||||||
|
|
||||||
import { ICoreState, MsgProps } from "./core_state";
|
import {
|
||||||
|
ICoreState,
|
||||||
|
MsgProps,
|
||||||
|
UIProps,
|
||||||
|
ctrlOn,
|
||||||
|
ctrlHidden,
|
||||||
|
} from "./core_state";
|
||||||
import { LoginProps } from "./pane_login";
|
import { LoginProps } from "./pane_login";
|
||||||
import { updater } from "./state_updater";
|
import { updater } from "./state_updater";
|
||||||
import { Flexbox } from "./layout/flexbox";
|
import { Flexbox } from "./layout/flexbox";
|
||||||
import { getIcon } from "./visual/icons";
|
import { settingsDialogCtrl } from "./layers";
|
||||||
|
|
||||||
export interface State {}
|
export interface State {}
|
||||||
export interface Props {
|
export interface Props {
|
||||||
login: LoginProps;
|
login: LoginProps;
|
||||||
msg: MsgProps;
|
msg: MsgProps;
|
||||||
|
ui: UIProps;
|
||||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +27,8 @@ export class TopBar extends React.Component<Props, State, {}> {
|
||||||
super(p);
|
super(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
showSettings = () => {
|
openSettings = () => {
|
||||||
updater().setControlOption("settingsDialog", "on");
|
updater().setControlOption(settingsDialogCtrl, ctrlOn);
|
||||||
this.props.update(updater().updateUI);
|
this.props.update(updater().updateUI);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +73,10 @@ export class TopBar extends React.Component<Props, State, {}> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const showLogin = this.props.login.authed ? "" : "hidden";
|
const showLogin = this.props.login.authed ? "" : "hidden";
|
||||||
|
const showSettings =
|
||||||
|
this.props.ui.control.controls.get(settingsDialogCtrl) === ctrlHidden
|
||||||
|
? "hidden"
|
||||||
|
: "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="top-bar">
|
<div id="top-bar">
|
||||||
|
@ -82,7 +93,10 @@ export class TopBar extends React.Component<Props, State, {}> {
|
||||||
|
|
||||||
<Flexbox
|
<Flexbox
|
||||||
children={List([
|
children={List([
|
||||||
<button onClick={this.showSettings} className={`margin-r-m`}>
|
<button
|
||||||
|
onClick={this.openSettings}
|
||||||
|
className={`margin-r-m ${showSettings}`}
|
||||||
|
>
|
||||||
{this.props.msg.pkg.get("settings")}
|
{this.props.msg.pkg.get("settings")}
|
||||||
{/* {getIcon("RiSettings4Line", "1.8rem", "cyan0")} */}
|
{/* {getIcon("RiSettings4Line", "1.8rem", "cyan0")} */}
|
||||||
</button>,
|
</button>,
|
||||||
|
|
|
@ -12,6 +12,9 @@ import { RiCheckboxFill } from "@react-icons/all-files/ri/RiCheckboxFill";
|
||||||
import { RiMenuFill } from "@react-icons/all-files/ri/RiMenuFill";
|
import { RiMenuFill } from "@react-icons/all-files/ri/RiMenuFill";
|
||||||
import { RiInformationFill } from "@react-icons/all-files/ri/RiInformationFill";
|
import { RiInformationFill } from "@react-icons/all-files/ri/RiInformationFill";
|
||||||
import { RiDeleteBin2Fill } from "@react-icons/all-files/ri/RiDeleteBin2Fill";
|
import { RiDeleteBin2Fill } from "@react-icons/all-files/ri/RiDeleteBin2Fill";
|
||||||
|
import { RiArchiveDrawerFill } from "@react-icons/all-files/ri/RiArchiveDrawerFill";
|
||||||
|
import { RiFileList2Fill } from "@react-icons/all-files/ri/RiFileList2Fill";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { colorClass } from "./colors";
|
import { colorClass } from "./colors";
|
||||||
|
@ -23,6 +26,7 @@ export interface IconProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const icons = Map<string, IconType>({
|
const icons = Map<string, IconType>({
|
||||||
|
RiFileList2Fill: RiFileList2Fill,
|
||||||
RiFolder2Fill: RiFolder2Fill,
|
RiFolder2Fill: RiFolder2Fill,
|
||||||
RiShareBoxLine: RiShareBoxLine,
|
RiShareBoxLine: RiShareBoxLine,
|
||||||
RiUploadCloudFill: RiUploadCloudFill,
|
RiUploadCloudFill: RiUploadCloudFill,
|
||||||
|
@ -33,6 +37,7 @@ const icons = Map<string, IconType>({
|
||||||
RiMenuFill: RiMenuFill,
|
RiMenuFill: RiMenuFill,
|
||||||
RiInformationFill: RiInformationFill,
|
RiInformationFill: RiInformationFill,
|
||||||
RiDeleteBin2Fill: RiDeleteBin2Fill,
|
RiDeleteBin2Fill: RiDeleteBin2Fill,
|
||||||
|
RiArchiveDrawerFill: RiArchiveDrawerFill,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function getIconWithProps(
|
export function getIconWithProps(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue