add: comic reader page up/down btn
This commit is contained in:
parent
d961e8166d
commit
e83a6bbe2b
@ -198,8 +198,7 @@ export const Headline = (prop: {
|
||||
}
|
||||
}}
|
||||
value={search}
|
||||
>
|
||||
</StyledInputBase>
|
||||
/>
|
||||
</StyledSearchBar>
|
||||
{isLogin
|
||||
? (
|
||||
@ -250,12 +249,10 @@ export const Headline = (prop: {
|
||||
display: "flex",
|
||||
flexFlow: "column",
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing(3),
|
||||
marginTop: theme.spacing(6),
|
||||
padding: "0px",
|
||||
marginTop: "64px",
|
||||
}}
|
||||
>
|
||||
<div style={{}}></div>
|
||||
{prop.children}
|
||||
>{prop.children}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
|
5
src/client/component/pagepad.tsx
Normal file
5
src/client/component/pagepad.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import { styled } from "@mui/material";
|
||||
|
||||
export const PagePad = styled("div")(({theme})=>({
|
||||
padding: theme.spacing(3)
|
||||
}))
|
@ -2,12 +2,15 @@ import { ArrowBack as ArrowBackIcon } from "@mui/icons-material";
|
||||
import { Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { BackItem, CommonMenuList, Headline, NavList } from "../component/mod";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
export const NotFoundPage = () => {
|
||||
const menu = CommonMenuList();
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<Typography variant="h2">404 Not Found</Typography>
|
||||
<PagePad>
|
||||
<Typography variant="h2">404 Not Found</Typography>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
};
|
||||
|
@ -6,6 +6,7 @@ import { LoadingCircle } from "../component/loading";
|
||||
import { CommonMenuList, ContentInfo, Headline } from "../component/mod";
|
||||
import { NotFoundPage } from "./404";
|
||||
import { getPresenter } from "./reader/reader";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||
export const makeComicReaderUrl = (id: number) => `/doc/${id}/reader`;
|
||||
@ -79,7 +80,7 @@ export const DocumentAbout = (prop?: {}) => {
|
||||
if (match == null) {
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
const id = Number.parseInt(match.id);
|
||||
const id = Number.parseInt(match.id ?? "NaN");
|
||||
const [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound: false });
|
||||
const menu_list = (link?: string) => <CommonMenuList url={link}></CommonMenuList>;
|
||||
|
||||
@ -95,25 +96,33 @@ export const DocumentAbout = (prop?: {}) => {
|
||||
if (isNaN(id)) {
|
||||
return (
|
||||
<Headline menu={menu_list()}>
|
||||
<PagePad>
|
||||
<Typography variant="h2">Oops. Invalid ID</Typography>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
} else if (info.notfound) {
|
||||
return (
|
||||
<Headline menu={menu_list()}>
|
||||
<PagePad>
|
||||
<Typography variant="h2">Content has been removed.</Typography>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
} else if (info.doc === undefined) {
|
||||
return (
|
||||
<Headline menu={menu_list()}>
|
||||
<PagePad>
|
||||
<LoadingCircle />
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Headline menu={menu_list()}>
|
||||
<PagePad>
|
||||
<ContentInfo document={info.doc}></ContentInfo>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { Stack } from "@mui/material";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import { UserContext } from "../state";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
const useStyles = (theme: Theme) => ({
|
||||
paper: {
|
||||
@ -127,6 +128,7 @@ export function DifferencePage() {
|
||||
const menu = CommonMenuList();
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<PagePad>
|
||||
{(ctx.username == "admin")
|
||||
? (
|
||||
<div>
|
||||
@ -136,6 +138,7 @@ export function DifferencePage() {
|
||||
</div>
|
||||
)
|
||||
: <Typography variant="h2">Not Allowed : please login as an admin</Typography>}
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import { toQueryString } from "../accessor/util";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { QueryStringToMap } from "../accessor/util";
|
||||
import { useIsElementInViewport } from "./reader/reader";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
export type GalleryProp = {
|
||||
option?: QueryListOption;
|
||||
@ -70,8 +71,7 @@ export const GalleryInfo = (props: GalleryProp) => {
|
||||
)}
|
||||
{props.option.allow_tag !== undefined
|
||||
&& props.option.allow_tag.map(x => (
|
||||
<TagChip key={x} tagname={decodeURIComponent(x)} label={decodeURIComponent(x)}>
|
||||
</TagChip>
|
||||
<TagChip key={x} tagname={decodeURIComponent(x)} label={decodeURIComponent(x)}/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
@ -126,7 +126,9 @@ export const Gallery = () => {
|
||||
option.limit = typeof query["limit"] === "string" ? parseInt(query["limit"]) : undefined;
|
||||
return (
|
||||
<Headline menu={menu_list}>
|
||||
<PagePad>
|
||||
<GalleryInfo diff={location.search} option={query}></GalleryInfo>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import { UserContext } from "../state";
|
||||
import { doLogin as doSessionLogin } from "../state";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
export const LoginPage = () => {
|
||||
const theme = useTheme();
|
||||
@ -48,39 +49,41 @@ export const LoginPage = () => {
|
||||
const menu = CommonMenuList();
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<Paper style={{ width: theme.spacing(40), padding: theme.spacing(4), alignSelf: "center" }}>
|
||||
<Typography variant="h4">Login</Typography>
|
||||
<div style={{ minHeight: theme.spacing(2) }}></div>
|
||||
<form style={{ display: "flex", flexFlow: "column", alignItems: "stretch" }}>
|
||||
<TextField
|
||||
label="username"
|
||||
onChange={(e) => setUserLoginInfo({ ...userLoginInfo, username: e.target.value ?? "" })}
|
||||
>
|
||||
</TextField>
|
||||
<TextField
|
||||
label="password"
|
||||
type="password"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") doLogin();
|
||||
}}
|
||||
onChange={(e) => setUserLoginInfo({ ...userLoginInfo, password: e.target.value ?? "" })}
|
||||
/>
|
||||
<PagePad>
|
||||
<Paper style={{ width: theme.spacing(40), padding: theme.spacing(4), alignSelf: "center" }}>
|
||||
<Typography variant="h4">Login</Typography>
|
||||
<div style={{ minHeight: theme.spacing(2) }}></div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button onClick={doLogin}>login</Button>
|
||||
<Button>signin</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Paper>
|
||||
<Dialog open={openDialog.open} onClose={handleDialogClose}>
|
||||
<DialogTitle>Login Failed</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>detail : {openDialog.message}</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleDialogClose} color="primary" autoFocus>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<form style={{ display: "flex", flexFlow: "column", alignItems: "stretch" }}>
|
||||
<TextField
|
||||
label="username"
|
||||
onChange={(e) => setUserLoginInfo({ ...userLoginInfo, username: e.target.value ?? "" })}
|
||||
>
|
||||
</TextField>
|
||||
<TextField
|
||||
label="password"
|
||||
type="password"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") doLogin();
|
||||
}}
|
||||
onChange={(e) => setUserLoginInfo({ ...userLoginInfo, password: e.target.value ?? "" })}
|
||||
/>
|
||||
<div style={{ minHeight: theme.spacing(2) }}></div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button onClick={doLogin}>login</Button>
|
||||
<Button>signin</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Paper>
|
||||
<Dialog open={openDialog.open} onClose={handleDialogClose}>
|
||||
<DialogTitle>Login Failed</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>detail : {openDialog.message}</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleDialogClose} color="primary" autoFocus>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
import React, { useContext, useState } from "react";
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import { UserContext } from "../state";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
const useStyles = (theme: Theme) => ({
|
||||
paper: {
|
||||
@ -77,71 +78,74 @@ export function ProfilePage() {
|
||||
};
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<Paper /*className={classes.paper}*/>
|
||||
<Grid container direction="column" alignItems="center">
|
||||
<Grid item>
|
||||
<Typography variant="h4">{userctx.username}</Typography>
|
||||
<PagePad>
|
||||
|
||||
<Paper /*className={classes.paper}*/>
|
||||
<Grid container direction="column" alignItems="center">
|
||||
<Grid item>
|
||||
<Typography variant="h4">{userctx.username}</Typography>
|
||||
</Grid>
|
||||
<Divider></Divider>
|
||||
<Grid item>
|
||||
Permission
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{permission_list.length == 0 ? "-" : permission_list}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button onClick={handle_open}>Password Reset</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Divider></Divider>
|
||||
<Grid item>
|
||||
Permission
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{permission_list.length == 0 ? "-" : permission_list}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button onClick={handle_open}>Password Reset</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
<Dialog open={pw_open} onClose={handle_close}>
|
||||
<DialogTitle>Password Reset</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>type the old and new password</Typography>
|
||||
<div /*className={classes.formfield}*/>
|
||||
{(!isElectronContent) && (
|
||||
</Paper>
|
||||
<Dialog open={pw_open} onClose={handle_close}>
|
||||
<DialogTitle>Password Reset</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>type the old and new password</Typography>
|
||||
<div /*className={classes.formfield}*/>
|
||||
{(!isElectronContent) && (
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
type="password"
|
||||
label="old password"
|
||||
value={oldpw}
|
||||
onChange={(e) => setOldpw(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
)}
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
type="password"
|
||||
label="old password"
|
||||
value={oldpw}
|
||||
onChange={(e) => setOldpw(e.target.value)}
|
||||
label="new password"
|
||||
value={newpw}
|
||||
onChange={e => setNewpw(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
)}
|
||||
<TextField
|
||||
margin="dense"
|
||||
type="password"
|
||||
label="new password"
|
||||
value={newpw}
|
||||
onChange={e => setNewpw(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
<TextField
|
||||
margin="dense"
|
||||
type="password"
|
||||
label="new password check"
|
||||
value={newpwch}
|
||||
onChange={e => setNewpwch(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handle_close} color="primary">Cancel</Button>
|
||||
<Button onClick={handle_ok} color="primary">Ok</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog open={msg_dialog.opened} onClose={() => set_msg_dialog({ opened: false, msg: "" })}>
|
||||
<DialogTitle>Alert!</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>{msg_dialog.msg}</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => set_msg_dialog({ opened: false, msg: "" })} color="primary">Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<TextField
|
||||
margin="dense"
|
||||
type="password"
|
||||
label="new password check"
|
||||
value={newpwch}
|
||||
onChange={e => setNewpwch(e.target.value)}
|
||||
>
|
||||
</TextField>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handle_close} color="primary">Cancel</Button>
|
||||
<Button onClick={handle_ok} color="primary">Ok</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Dialog open={msg_dialog.opened} onClose={() => set_msg_dialog({ opened: false, msg: "" })}>
|
||||
<DialogTitle>Alert!</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>{msg_dialog.msg}</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => set_msg_dialog({ opened: false, msg: "" })} color="primary">Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Typography, useTheme } from "@mui/material";
|
||||
import { Typography, styled } from "@mui/material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Document } from "../../accessor/document";
|
||||
|
||||
@ -13,6 +13,21 @@ export type PresentableTag = {
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
const ViewMain = styled("div")(({ theme }) => ({
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
height: "calc(100vh - 64px)",
|
||||
position: "relative",
|
||||
}));
|
||||
const CurrentView = styled("img")(({theme})=>({
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
top:"50%",
|
||||
left:"50%",
|
||||
transform: "translate(-50%,-50%)",
|
||||
position: "absolute"
|
||||
}));
|
||||
|
||||
export const ComicReader = (props: { doc: Document }) => {
|
||||
const additional = props.doc.additional;
|
||||
const [curPage, setCurPage] = useState(0);
|
||||
@ -21,13 +36,13 @@ export const ComicReader = (props: { doc: Document }) => {
|
||||
return <Typography>Error. DB error. page restriction</Typography>;
|
||||
}
|
||||
const PageDown = () => setCurPage(Math.max(curPage - 1, 0));
|
||||
const PageUP = () => setCurPage(Math.min(curPage + 1, page - 1));
|
||||
const PageUp = () => setCurPage(Math.min(curPage + 1, page - 1));
|
||||
const page: number = additional["page"] as number;
|
||||
const onKeyUp = (e: KeyboardEvent) => {
|
||||
if (e.code === "ArrowLeft") {
|
||||
PageDown();
|
||||
} else if (e.code === "ArrowRight") {
|
||||
PageUP();
|
||||
PageUp();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
@ -38,14 +53,14 @@ export const ComicReader = (props: { doc: Document }) => {
|
||||
});
|
||||
// theme.mixins.toolbar.minHeight;
|
||||
return (
|
||||
<div style={{ overflow: "hidden", alignSelf: "center" }}>
|
||||
<img
|
||||
onClick={PageUP}
|
||||
<ViewMain>
|
||||
<div onClick={PageDown} style={{left:"0", width: "50%", position:"absolute", height: "100%", zIndex:100}}></div>
|
||||
<CurrentView
|
||||
onClick={PageUp}
|
||||
src={`/api/doc/${props.doc.id}/comic/${curPage}`}
|
||||
style={{ maxWidth: "100%", maxHeight: "calc(100vh - 64px)" }}
|
||||
>
|
||||
</img>
|
||||
</div>
|
||||
></CurrentView>
|
||||
<div onClick={PageUp} style={{right:"0", width: "50%", position:"absolute", height: "100%", zIndex:100}}></div>
|
||||
</ViewMain>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,14 +2,17 @@ import { ArrowBack as ArrowBackIcon } from "@mui/icons-material";
|
||||
import { Paper, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { BackItem, CommonMenuList, Headline, NavList } from "../component/mod";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
export const SettingPage = () => {
|
||||
const menu = CommonMenuList();
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<Paper>
|
||||
<Typography variant="h2">Setting</Typography>
|
||||
</Paper>
|
||||
<PagePad>
|
||||
<Paper>
|
||||
<Typography variant="h2">Setting</Typography>
|
||||
</Paper>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ import { DataGrid, GridColDef } from "@mui/x-data-grid";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { LoadingCircle } from "../component/loading";
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import { PagePad } from "../component/pagepad";
|
||||
|
||||
type TagCount = {
|
||||
tag_name: string;
|
||||
@ -67,7 +68,9 @@ export const TagsPage = () => {
|
||||
const menu = CommonMenuList();
|
||||
return (
|
||||
<Headline menu={menu}>
|
||||
<TagTable></TagTable>
|
||||
<PagePad>
|
||||
<TagTable></TagTable>
|
||||
</PagePad>
|
||||
</Headline>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user