mui upgrade
This commit is contained in:
parent
0081229f86
commit
7a3fdce4dc
@ -6,11 +6,11 @@
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com;
|
||||
font-src 'self' fonts.gstatic.com">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/dist/css/style.css">
|
||||
<link rel="stylesheet" href="/dist/bundle.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/dist/js/bundle.js"></script>
|
||||
<script src="/dist/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-typescript",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/proposal-class-properties",
|
||||
"@babel/proposal-object-rest-spread"
|
||||
]
|
||||
}
|
@ -15,6 +15,8 @@ export class FetchFailError implements Error{
|
||||
}
|
||||
}
|
||||
export class ClientDocumentAccessor implements DocumentAccessor{
|
||||
search: (search_word: string) => Promise<Document[]>;
|
||||
addList: (content_list: DocumentBody[]) => Promise<number[]>;
|
||||
async findByPath(basepath: string, filename?: string): Promise<Document[]>{
|
||||
throw new Error("not allowed");
|
||||
};
|
||||
|
@ -1,46 +1,50 @@
|
||||
import React, { createContext, useEffect, useRef, useState } from 'react';
|
||||
import ReactDom from 'react-dom';
|
||||
import {BrowserRouter, Redirect, Route, Switch as RouterSwitch} from 'react-router-dom';
|
||||
import { Gallery, DocumentAbout, LoginPage, NotFoundPage, ProfilePage,DifferencePage, SettingPage} from './page/mod';
|
||||
import {getInitialValue, UserContext} from './state';
|
||||
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
|
||||
import { Gallery, DocumentAbout, LoginPage, NotFoundPage, ProfilePage, DifferencePage, SettingPage } from './page/mod';
|
||||
import { getInitialValue, UserContext } from './state';
|
||||
import { ThemeProvider, createTheme } from '@mui/material';
|
||||
|
||||
import './css/style.css';
|
||||
|
||||
const theme = createTheme();
|
||||
|
||||
const App = () => {
|
||||
const [user,setUser] = useState("");
|
||||
const [userPermission,setUserPermission] = useState<string[]>([]);
|
||||
(async ()=>{
|
||||
const {username,permission} = await getInitialValue();
|
||||
if(username !== user){
|
||||
const [user, setUser] = useState("");
|
||||
const [userPermission, setUserPermission] = useState<string[]>([]);
|
||||
(async () => {
|
||||
const { username, permission } = await getInitialValue();
|
||||
if (username !== user) {
|
||||
setUser(username);
|
||||
setUserPermission(permission);
|
||||
}
|
||||
})();
|
||||
//useEffect(()=>{});
|
||||
return (
|
||||
<UserContext.Provider value={{
|
||||
username:user,
|
||||
setUsername:setUser,
|
||||
permission:userPermission,
|
||||
setPermission:setUserPermission}}>
|
||||
<BrowserRouter>
|
||||
<RouterSwitch>
|
||||
<Route path="/" exact render={()=><Redirect to='/search?'/>}></Route>
|
||||
<Route path="/search" render={()=><Gallery />}></Route>
|
||||
<Route path="/doc" render={(prop)=><DocumentAbout {...prop}/>}></Route>
|
||||
<Route path="/login" render={()=><LoginPage></LoginPage>}/>
|
||||
<Route path="/profile" component={ProfilePage}></Route>
|
||||
<Route path="/difference" component={DifferencePage}></Route>
|
||||
<Route path="/setting" component={SettingPage}></Route>
|
||||
<Route>
|
||||
<NotFoundPage/>
|
||||
</Route>
|
||||
</RouterSwitch>
|
||||
</BrowserRouter>
|
||||
</UserContext.Provider>);
|
||||
<UserContext.Provider value={{
|
||||
username: user,
|
||||
setUsername: setUser,
|
||||
permission: userPermission,
|
||||
setPermission: setUserPermission
|
||||
}}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate replace to='/search?' />} />
|
||||
<Route path="/search" element={<Gallery />} />
|
||||
<Route path="/doc" element={<DocumentAbout />}></Route>
|
||||
<Route path="/login" element={<LoginPage></LoginPage>} />
|
||||
<Route path="/profile" element={<ProfilePage />}></Route>
|
||||
<Route path="/difference" element={<DifferencePage />}></Route>
|
||||
<Route path="/setting" element={<SettingPage />}></Route>
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</ThemeProvider>
|
||||
</UserContext.Provider>);
|
||||
};
|
||||
|
||||
ReactDom.render(
|
||||
<App/>,
|
||||
<App />,
|
||||
document.getElementById("root")
|
||||
)
|
||||
);
|
33
src/client/build.ts
Normal file
33
src/client/build.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import esbuild from 'esbuild';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const result = await esbuild.build({
|
||||
entryPoints: ['app.tsx'],
|
||||
bundle: true,
|
||||
outfile: '../../dist/bundle.js',
|
||||
platform: 'browser',
|
||||
sourcemap: true,
|
||||
minify: true,
|
||||
target: ['chrome100', 'firefox100'],
|
||||
watch: {
|
||||
onRebuild: async (err, _result) => {
|
||||
if (err) {
|
||||
console.error('watch build failed: ',err);
|
||||
}
|
||||
else{
|
||||
console.log('watch build success');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log("watching...");
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().then((res) => {
|
||||
});
|
@ -1,23 +1,16 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink } from 'react-router-dom';
|
||||
import React, { } from 'react';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { Document } from '../accessor/document';
|
||||
import { LoadingCircle } from '../component/loading';
|
||||
import { Link, Paper, makeStyles, Theme, Box, useTheme, Typography } from '@material-ui/core';
|
||||
|
||||
import { Link, Paper, Theme, Box, useTheme, Typography } from '@mui/material';
|
||||
import { ThumbnailContainer } from '../page/reader/reader';
|
||||
import { TagChip } from '../component/tagchip';
|
||||
import { ComicReader } from '../page/reader/comic';
|
||||
|
||||
|
||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||
export const makeContentReaderUrl = (id: number) => `/doc/${id}/reader`;
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
root: {
|
||||
display: "flex",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}
|
||||
},
|
||||
const useStyles = ((theme: Theme) => ({
|
||||
thumbnail_content: {
|
||||
maxHeight: '400px',
|
||||
maxWidth: 'min(400px, 100vw)',
|
||||
@ -43,26 +36,26 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
overflowY: 'hidden',
|
||||
alignItems: 'baseline',
|
||||
},
|
||||
short_subinfoContainer:{
|
||||
[theme.breakpoints.down("md")]:{
|
||||
display:'none',
|
||||
short_subinfoContainer: {
|
||||
[theme.breakpoints.down("md")]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
short_root:{
|
||||
overflowY:'hidden',
|
||||
display:'flex',
|
||||
short_root: {
|
||||
overflowY: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
[theme.breakpoints.up("sm")]:{
|
||||
height:200,
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
height: 200,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
},
|
||||
short_thumbnail_anchor:{
|
||||
short_thumbnail_anchor: {
|
||||
background: '#272733',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
[theme.breakpoints.up("sm")]:{
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: theme.spacing(25),
|
||||
height: theme.spacing(25),
|
||||
flexShrink: 0,
|
||||
@ -84,66 +77,75 @@ export const ContentInfo = (props: {
|
||||
infoContainer?: string,
|
||||
subinfoContainer?: string
|
||||
},
|
||||
gallery?:string,
|
||||
short?:boolean
|
||||
gallery?: string,
|
||||
short?: boolean
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
//const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const document = props.document;
|
||||
const propclasses = props.classes ?? {};
|
||||
const rootName = props.short ? classes.short_root : classes.root;
|
||||
/*const rootName = props.short ? classes.short_root : classes.root;
|
||||
const thumbnail_anchor = props.short ? classes.short_thumbnail_anchor : "";
|
||||
const thumbnail_content = props.short ? classes.short_thumbnail_content :
|
||||
classes.thumbnail_content;
|
||||
const subinfoContainer = props.short ? classes.short_subinfoContainer :
|
||||
classes.subinfoContainer;
|
||||
return (<Paper className={propclasses.root ?? rootName} elevation={4}>
|
||||
<Link className={propclasses.thumbnail_anchor ?? thumbnail_anchor} component={RouterLink} to={{
|
||||
pathname:makeContentReaderUrl(document.id)
|
||||
classes.subinfoContainer;*/
|
||||
const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id);
|
||||
return (<Paper sx={{
|
||||
display: "flex",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}
|
||||
}} elevation={4}>
|
||||
<Link /*className={propclasses.thumbnail_anchor ?? thumbnail_anchor}*/ component={RouterLink} to={{
|
||||
pathname: makeContentReaderUrl(document.id)
|
||||
}}>
|
||||
{document.deleted_at === null ?
|
||||
(<ThumbnailContainer content={document}
|
||||
className={propclasses.thumbnail_content ?? thumbnail_content}/>)
|
||||
: (<Typography className={propclasses.thumbnail_content ?? thumbnail_content} variant='h4'>Deleted</Typography>)}
|
||||
{document.deleted_at === null ?
|
||||
(<ThumbnailContainer content={document}
|
||||
style={{
|
||||
maxHeight: '400px',
|
||||
maxWidth: 'min(400px, 100vw)',
|
||||
}}/>)
|
||||
: (<Typography/* className={propclasses.thumbnail_content ?? thumbnail_content} */ variant='h4'>Deleted</Typography>)}
|
||||
</Link>
|
||||
<Box className={propclasses.infoContainer ?? classes.infoContainer}>
|
||||
<Link variant='h5' color='inherit' component={RouterLink} to={{
|
||||
pathname: props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id),
|
||||
}}
|
||||
className={propclasses.title ?? classes.title}>
|
||||
<Box /*className={propclasses.infoContainer ?? classes.infoContainer}*/>
|
||||
<Link variant='h5' color='inherit' component={RouterLink} to={{pathname: url}}
|
||||
/*className={propclasses.title ?? classes.title}*/>
|
||||
{document.title}
|
||||
</Link>
|
||||
<Box className={propclasses.subinfoContainer ?? subinfoContainer}>
|
||||
{props.short ? (<Box className={propclasses.tag_list ?? classes.tag_list}>{document.tags.map(x =>
|
||||
(<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>)
|
||||
)}</Box>) : (
|
||||
<ComicDetailTag tags={document.tags} classes={({tag_list:classes.tag_list})}></ComicDetailTag>)
|
||||
<Box /*className={propclasses.subinfoContainer ?? subinfoContainer}*/>
|
||||
{props.short ? (<Box /*className={propclasses.tag_list ?? classes.tag_list}*/>{document.tags.map(x =>
|
||||
(<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>)
|
||||
)}</Box>) : (
|
||||
<ComicDetailTag tags={document.tags}/* classes={({tag_list:classes.tag_list})}*/ ></ComicDetailTag>)
|
||||
}
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>);
|
||||
}
|
||||
|
||||
function ComicDetailTag(prop:{tags:string[],classes:{
|
||||
function ComicDetailTag(prop: {
|
||||
tags: string[]/*classes:{
|
||||
tag_list:string
|
||||
}}){
|
||||
}*/}) {
|
||||
let allTag = prop.tags;
|
||||
const tagKind = ["artist","group","series","type","character"];
|
||||
let tagTable:{[kind:string]:string[]} = {};
|
||||
for(const kind of tagKind){
|
||||
const tags = allTag.filter(x => x.startsWith(kind+":")).map(x => x.slice(kind.length+1));
|
||||
const tagKind = ["artist", "group", "series", "type", "character"];
|
||||
let tagTable: { [kind: string]: string[] } = {};
|
||||
for (const kind of tagKind) {
|
||||
const tags = allTag.filter(x => x.startsWith(kind + ":")).map(x => x.slice(kind.length + 1));
|
||||
tagTable[kind] = tags;
|
||||
allTag = allTag.filter(x => !x.startsWith(kind+":"));
|
||||
allTag = allTag.filter(x => !x.startsWith(kind + ":"));
|
||||
}
|
||||
return (<React.Fragment>
|
||||
{tagKind.map(key=>(
|
||||
{tagKind.map(key => (
|
||||
<React.Fragment key={key}>
|
||||
<Typography variant='subtitle1'>{key}</Typography>
|
||||
<Box>{tagTable[key].length !== 0 ? tagTable[key].join(", ") : "N/A"}</Box>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<Typography variant='subtitle1'>Tags</Typography>
|
||||
<Box className={prop.classes.tag_list}>
|
||||
<Box /*lassName={prop.classes.tag_list}*/>
|
||||
{allTag.map(x => (<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>))}
|
||||
</Box>
|
||||
</React.Fragment>);
|
||||
|
@ -1,123 +1,77 @@
|
||||
import ReactDom from 'react-dom';
|
||||
import React, { ReactNode, useContext, useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {
|
||||
Button, CssBaseline, Divider, IconButton, List, ListItem, Drawer,
|
||||
AppBar, Toolbar, Typography, InputBase, ListItemIcon, ListItemText, Menu, MenuItem,
|
||||
Hidden, Tooltip, Link
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles, Theme, useTheme, fade } from '@material-ui/core/styles';
|
||||
import { ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle
|
||||
} from '@material-ui/icons';
|
||||
Hidden, Tooltip, Link, styled
|
||||
} from '@mui/material';
|
||||
import { alpha, Theme, useTheme } from '@mui/material/styles';
|
||||
import {
|
||||
ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle
|
||||
} from '@mui/icons-material';
|
||||
|
||||
import { Link as RouterLink, useRouteMatch } from 'react-router-dom';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { doLogout, UserContext } from '../state';
|
||||
|
||||
const drawerWidth = 240;
|
||||
const drawerWidth = 270;
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
root: {
|
||||
display: 'flex'
|
||||
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||
...theme.mixins.toolbar
|
||||
}));
|
||||
|
||||
const StyledDrawer = styled(Drawer)(({ theme }) => ({
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: drawerWidth,
|
||||
},
|
||||
appBar: {
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition: theme.transitions.create(['width', 'margin'], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen
|
||||
})
|
||||
}
|
||||
));
|
||||
const StyledSearchBar = styled('div')(({ theme }) => ({
|
||||
position: 'relative',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.15),
|
||||
'&:hover': {
|
||||
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||
},
|
||||
menuButton: {
|
||||
marginRight: 36
|
||||
marginLeft: 0,
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
marginLeft: theme.spacing(1),
|
||||
width: 'auto',
|
||||
},
|
||||
hide: {
|
||||
display: "none"
|
||||
},
|
||||
drawer: {
|
||||
flexShrink: 0,
|
||||
whiteSpace: "nowrap",
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: drawerWidth,
|
||||
},
|
||||
},
|
||||
drawerPaper: {
|
||||
width: drawerWidth
|
||||
},
|
||||
drawerClose: {
|
||||
overflowX: 'hidden',
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
width: theme.spacing(7) + 1,
|
||||
},
|
||||
},
|
||||
toolbar: {
|
||||
...theme.mixins.toolbar,
|
||||
},
|
||||
content: {
|
||||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing(3),
|
||||
},
|
||||
title: {
|
||||
display: 'none',
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
display: 'block'
|
||||
}
|
||||
},
|
||||
search: {
|
||||
position: 'relative',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: fade(theme.palette.common.white, 0.15),
|
||||
'&:hover': {
|
||||
backgroundColor: fade(theme.palette.common.white, 0.25),
|
||||
},
|
||||
marginRight: theme.spacing(2),
|
||||
marginLeft: 0,
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
marginLeft: theme.spacing(3),
|
||||
width: 'auto',
|
||||
},
|
||||
},
|
||||
searchIcon: {
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
inputRoot: {
|
||||
color: 'inherit'
|
||||
},
|
||||
inputInput: {
|
||||
}));
|
||||
const StyledInputBase = styled(InputBase)(({ theme }) => ({
|
||||
color: 'inherit',
|
||||
'& .MuiInputBase-input': {
|
||||
padding: theme.spacing(1, 1, 1, 0),
|
||||
// vertical padding + font size from searchIcon
|
||||
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
|
||||
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
||||
transition: theme.transitions.create('width'),
|
||||
width: '100%',
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: '20ch',
|
||||
"&:hover": {
|
||||
width: '25ch'
|
||||
}
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
width: '12ch',
|
||||
'&:focus': {
|
||||
width: '20ch',
|
||||
},
|
||||
},
|
||||
},
|
||||
grow: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
}));
|
||||
|
||||
const closedMixin = (theme: Theme) => ({
|
||||
overflowX: 'hidden',
|
||||
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||
});
|
||||
|
||||
export const Headline = (prop: {
|
||||
children?: React.ReactNode,
|
||||
classes?:{
|
||||
content?:string,
|
||||
toolbar?:string,
|
||||
classes?: {
|
||||
content?: string,
|
||||
toolbar?: string,
|
||||
},
|
||||
menu: React.ReactNode
|
||||
}) => {
|
||||
const [v, setv] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const toggleV = () => setv(!v);
|
||||
const handleProfileMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
|
||||
@ -137,39 +91,58 @@ export const Headline = (prop: {
|
||||
onClose={handleProfileMenuClose}
|
||||
>
|
||||
<MenuItem component={RouterLink} to='/profile'>Profile</MenuItem>
|
||||
<MenuItem onClick={async ()=>{handleProfileMenuClose(); await doLogout(); user_ctx.setUsername("");}}>Logout</MenuItem>
|
||||
<MenuItem onClick={async () => { handleProfileMenuClose(); await doLogout(); user_ctx.setUsername(""); }}>Logout</MenuItem>
|
||||
</Menu>);
|
||||
const drawer_contents = (<>
|
||||
<div className={classes.toolbar}>
|
||||
<DrawerHeader>
|
||||
<IconButton onClick={toggleV}>
|
||||
{theme.direction === "ltr" ? <ChevronLeft /> : <ChevronRight />}
|
||||
</IconButton>
|
||||
</div>
|
||||
</DrawerHeader>
|
||||
<Divider />
|
||||
{prop.menu}
|
||||
</>);
|
||||
return (<div className={classes.root}>
|
||||
return (<div style={{ display: 'flex' }}>
|
||||
<CssBaseline />
|
||||
<AppBar position="fixed" className={classes.appBar}>
|
||||
<AppBar position="fixed" sx={{
|
||||
zIndex: theme.zIndex.drawer + 1,
|
||||
transition: theme.transitions.create(['width', 'margin'], {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: theme.transitions.duration.leavingScreen
|
||||
})
|
||||
}}>
|
||||
<Toolbar>
|
||||
<IconButton color="inherit"
|
||||
aria-label="open drawer"
|
||||
onClick={toggleV}
|
||||
edge="start"
|
||||
className={classes.menuButton}>
|
||||
style={{ marginRight: 36 }}
|
||||
>
|
||||
<MenuIcon></MenuIcon>
|
||||
</IconButton>
|
||||
<Link variant="h5" noWrap className={classes.title} color="inherit" component={RouterLink} to="/">
|
||||
<Link variant="h5" noWrap sx={{
|
||||
display: 'none',
|
||||
[theme.breakpoints.up("sm")]: {
|
||||
display: 'block'
|
||||
}
|
||||
}} color="inherit" component={RouterLink} to="/">
|
||||
Ionian
|
||||
</Link>
|
||||
<div className={classes.grow}></div>
|
||||
<div className={classes.search}>
|
||||
<div className={classes.searchIcon}>
|
||||
<div style={{ flexGrow: 1 }}></div>
|
||||
<StyledSearchBar >
|
||||
<div style={{
|
||||
padding: theme.spacing(0, 2),
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<InputBase placeholder="search"
|
||||
classes={{ root: classes.inputRoot, input: classes.inputInput }}></InputBase>
|
||||
</div>
|
||||
<StyledInputBase placeholder="search"></StyledInputBase>
|
||||
</StyledSearchBar>
|
||||
{
|
||||
isLogin ?
|
||||
<IconButton
|
||||
@ -188,21 +161,35 @@ export const Headline = (prop: {
|
||||
{renderProfileMenu}
|
||||
<nav>
|
||||
<Hidden smUp implementation="css">
|
||||
<Drawer variant="temporary" anchor='left' open={v} onClose={toggleV}
|
||||
classes={{ paper: classes.drawerPaper }}>
|
||||
<StyledDrawer variant="temporary" anchor='left' open={v} onClose={toggleV}
|
||||
sx={{
|
||||
width: drawerWidth
|
||||
}}
|
||||
>
|
||||
{drawer_contents}
|
||||
</Drawer>
|
||||
</StyledDrawer>
|
||||
</Hidden>
|
||||
<Hidden xsDown implementation="css">
|
||||
<Drawer variant='permanent' anchor='left' className={[classes.drawer, classes.drawerClose].join(" ").trim()} classes={{
|
||||
paper: classes.drawerClose
|
||||
}}>
|
||||
<StyledDrawer variant='permanent' anchor='left'
|
||||
sx={{
|
||||
overflowX: 'hidden',
|
||||
width: theme.spacing(7) + 1,
|
||||
...closedMixin(theme),
|
||||
'& .MuiDrawer-paper': closedMixin(theme),
|
||||
}}>
|
||||
{drawer_contents}
|
||||
</Drawer>
|
||||
</StyledDrawer>
|
||||
</Hidden>
|
||||
</nav>
|
||||
<main className={prop.classes?.content ?? classes.content}>
|
||||
<div className={prop.classes?.toolbar ?? classes.toolbar}></div>
|
||||
<main style={{
|
||||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
flexGrow: 1,
|
||||
padding: theme.spacing(3),
|
||||
marginTop: theme.spacing(8),
|
||||
}}>
|
||||
<div style={{
|
||||
}} ></div>
|
||||
{prop.children}
|
||||
</main>
|
||||
</div>);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {Box, CircularProgress} from '@material-ui/core';
|
||||
import {Box, CircularProgress} from '@mui/material';
|
||||
|
||||
export const LoadingCircle = ()=>{
|
||||
return (<Box style={{alignSelf:'center'}}>
|
||||
|
@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import {List, ListItem, ListItemIcon, Tooltip, ListItemText, Divider} from '@material-ui/core';
|
||||
import {List, ListItem, ListItemIcon, Tooltip, ListItemText, Divider} from '@mui/material';
|
||||
import {ArrowBack as ArrowBackIcon, Settings as SettingIcon,
|
||||
Collections as CollectionIcon, VideoLibrary as VideoIcon, Home as HomeIcon,
|
||||
Folder as FolderIcon } from '@material-ui/icons';
|
||||
import {Link as RouterLink, useHistory} from 'react-router-dom';
|
||||
Folder as FolderIcon } from '@mui/icons-material';
|
||||
import {Link as RouterLink} from 'react-router-dom';
|
||||
|
||||
export const NavItem = (props:{name:string,to:string, icon:React.ReactElement<any,any>})=>{
|
||||
const history = useHistory();
|
||||
return (<ListItem button key={props.name} component={RouterLink} to={props.to}>
|
||||
<ListItemIcon>
|
||||
<Tooltip title={props.name.toLocaleLowerCase()} placement="bottom">
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import {ChipTypeMap} from '@material-ui/core/Chip';
|
||||
import { Chip, colors } from '@material-ui/core';
|
||||
import {useTheme, makeStyles, Theme, emphasize, fade} from '@material-ui/core/styles';
|
||||
import {ChipTypeMap} from '@mui/material/Chip';
|
||||
import { Chip, colors } from '@mui/material';
|
||||
import { Theme, emphasize} from '@mui/material/styles';
|
||||
import {Link as RouterLink} from 'react-router-dom';
|
||||
|
||||
type TagChipStyleProp = {
|
||||
color: string
|
||||
}
|
||||
|
||||
const useTagStyles = makeStyles((theme:Theme)=>({
|
||||
const useTagStyles = ((theme:Theme)=>({
|
||||
root:(props:TagChipStyleProp)=>({
|
||||
color: theme.palette.getContrastText(props.color),
|
||||
backgroundColor: props.color,
|
||||
@ -27,14 +27,14 @@ const useTagStyles = makeStyles((theme:Theme)=>({
|
||||
color: (props:TagChipStyleProp)=>props.color,
|
||||
border: (props:TagChipStyleProp)=> `1px solid ${props.color}`,
|
||||
'$clickable&:hover, $clickable&:focus, $deletable&:focus': {
|
||||
backgroundColor:(props:TagChipStyleProp)=>fade(props.color,theme.palette.action.hoverOpacity),
|
||||
//backgroundColor:(props:TagChipStyleProp)=> (props.color,theme.palette.action.hoverOpacity),
|
||||
},
|
||||
},
|
||||
icon:{
|
||||
color:"inherit",
|
||||
},
|
||||
deleteIcon:{
|
||||
color:(props:TagChipStyleProp)=>fade(theme.palette.getContrastText(props.color),0.7),
|
||||
//color:(props:TagChipStyleProp)=> (theme.palette.getContrastText(props.color),0.7),
|
||||
"&:hover, &:active":{
|
||||
color:(props:TagChipStyleProp)=>theme.palette.getContrastText(props.color),
|
||||
}
|
||||
@ -59,10 +59,8 @@ type ColorChipProp = Omit<ChipTypeMap['props'],"color"> & TagChipStyleProp & {
|
||||
|
||||
export const ColorChip = (props:ColorChipProp)=>{
|
||||
const {color,...rest} = props;
|
||||
const classes = useTagStyles({color : color !== "default" ? color : "#000"});
|
||||
return <Chip color="default" classes={{
|
||||
...(color !== "default" ? classes : {})
|
||||
}} {...rest}></Chip>;
|
||||
//const classes = useTagStyles({color : color !== "default" ? color : "#000"});
|
||||
return <Chip color="default" {...rest}></Chip>;
|
||||
}
|
||||
|
||||
type TagChipProp = Omit<ChipTypeMap['props'],"color"> & {
|
||||
|
@ -1,52 +1,20 @@
|
||||
{
|
||||
"name": "ionian-client",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build:dev": "webpack --mode development",
|
||||
"build:prod": "webpack --mode production",
|
||||
"build:watch": "webpack --mode development -w",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"browserslist": {
|
||||
"production": [
|
||||
"> 10%"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.2",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@mui/material": "^5.0.3",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-router-dom": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
||||
"@babel/preset-env": "^7.12.11",
|
||||
"@babel/preset-react": "^7.12.10",
|
||||
"@babel/preset-typescript": "^7.12.7",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^8.2.2",
|
||||
"css-loader": "^5.0.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"mini-css-extract-plugin": "^1.3.3",
|
||||
"style-loader": "^2.0.0",
|
||||
"ts-json-schema-generator": "^0.82.0",
|
||||
"typescript": "^4.1.3",
|
||||
"webpack": "^5.15.0",
|
||||
"webpack-cli": "^4.3.1"
|
||||
}
|
||||
"name": "ionian_client",
|
||||
"version": "0.0.1",
|
||||
"description": "client of ionian",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
"@mui/icons-material": "^5.6.2",
|
||||
"@mui/material": "^5.6.2",
|
||||
"@types/react": "^18.0.5",
|
||||
"@types/react-dom": "^18.0.1",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.14.36",
|
||||
"ts-node": "^10.7.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import {Typography} from '@material-ui/core';
|
||||
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
||||
import {Typography} from '@mui/material';
|
||||
import {ArrowBack as ArrowBackIcon} from '@mui/icons-material';
|
||||
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
||||
|
||||
export const NotFoundPage = ()=>{
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink, useParams, useLocation } from 'react-router-dom';
|
||||
import React, { useState, useEffect} from 'react';
|
||||
import { Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||||
import DocumentAccessor, { Document } from '../accessor/document';
|
||||
import { LoadingCircle } from '../component/loading';
|
||||
import { Link, Paper, makeStyles, Theme, Box, useTheme, Typography } from '@material-ui/core';
|
||||
import {ArrowBack as ArrowBackIcon } from '@material-ui/icons';
|
||||
import { Theme, Typography } from '@mui/material';
|
||||
import { getPresenter } from './reader/reader';
|
||||
import { BackItem, CommonMenuList, ContentInfo, Headline, NavItem, NavList } from '../component/mod';
|
||||
import { CommonMenuList, ContentInfo, Headline } from '../component/mod';
|
||||
import {NotFoundPage} from './404';
|
||||
|
||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||
@ -16,7 +15,7 @@ type DocumentState = {
|
||||
notfound: boolean,
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme:Theme)=>({
|
||||
const styles = ((theme:Theme)=>({
|
||||
noPaddingContent:{
|
||||
display:'flex',
|
||||
flexDirection: 'column',
|
||||
@ -28,12 +27,13 @@ const useStyles = makeStyles((theme:Theme)=>({
|
||||
}
|
||||
}));
|
||||
|
||||
export const DocumentAbout = (prop: { match: MatchType }) => {
|
||||
const match = useRouteMatch<{id:string}>("/doc/:id");
|
||||
export const DocumentAbout = (prop?: {}) => {
|
||||
const location = useLocation();
|
||||
const match = useParams<{id:string}>();
|
||||
if (match == null) {
|
||||
throw new Error("unreachable");
|
||||
}
|
||||
const id = Number.parseInt(match.params['id']);
|
||||
const id = Number.parseInt(match.id);
|
||||
const [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound:false });
|
||||
const menu_list = (link?:string) => <CommonMenuList url={link}></CommonMenuList>;
|
||||
|
||||
@ -45,7 +45,7 @@ export const DocumentAbout = (prop: { match: MatchType }) => {
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
const classes = useStyles();
|
||||
|
||||
if (isNaN(id)) {
|
||||
return (
|
||||
<Headline menu={menu_list()}>
|
||||
@ -68,23 +68,20 @@ export const DocumentAbout = (prop: { match: MatchType }) => {
|
||||
}
|
||||
else{
|
||||
const ReaderPage = getPresenter(info.doc);
|
||||
return (<Switch>
|
||||
<Route exact path={`${prop.match.path}/:id`}>
|
||||
return (<Routes>
|
||||
<Route path={`:id`}>
|
||||
<Headline menu={menu_list()}>
|
||||
<ContentInfo document={info.doc}></ContentInfo>
|
||||
</Headline>
|
||||
</Route>
|
||||
<Route exact path={`${prop.match.path}/:id/reader`}>
|
||||
<Headline menu={menu_list(`${prop.match.path}/${id}`)} classes={{
|
||||
content:classes.noPaddingContent,
|
||||
toolbar:classes.noPaddingToolbar
|
||||
}}>
|
||||
<Route path={`:id/reader`}>
|
||||
<Headline menu={menu_list(location.pathname)}>
|
||||
<ReaderPage doc={info.doc}></ReaderPage>
|
||||
</Headline>
|
||||
</Route>
|
||||
<Route>
|
||||
<NotFoundPage></NotFoundPage>
|
||||
</Route>
|
||||
</Switch>);
|
||||
</Routes>);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import { UserContext } from "../state";
|
||||
import { Box, Grid, Paper, Typography,Button, makeStyles, Theme } from "@material-ui/core";
|
||||
import { Box, Grid, Paper, Typography,Button, Theme } from "@mui/material";
|
||||
import {Stack} from '@mui/material';
|
||||
|
||||
const useStyles = makeStyles((theme:Theme)=>({
|
||||
const useStyles = ((theme:Theme)=>({
|
||||
paper:{
|
||||
padding: theme.spacing(2),
|
||||
},
|
||||
@ -30,12 +30,12 @@ function TypeDifference(prop:{
|
||||
onCommit:(v:{type:string,path:string})=>void,
|
||||
onCommitAll:(type:string) => void
|
||||
}){
|
||||
const classes = useStyles();
|
||||
//const classes = useStyles();
|
||||
const x = prop.content;
|
||||
const [button_disable,set_disable] = useState(false);
|
||||
|
||||
return (<Paper className={classes.paper}>
|
||||
<Box className={classes.contentTitle}>
|
||||
return (<Paper /*className={classes.paper}*/>
|
||||
<Box /*className={classes.contentTitle}*/>
|
||||
<Typography variant='h3' >{x.type}</Typography>
|
||||
<Button variant="contained" key={x.type} onClick={()=>{
|
||||
set_disable(true);
|
||||
@ -44,7 +44,7 @@ function TypeDifference(prop:{
|
||||
}}>Commit all</Button>
|
||||
</Box>
|
||||
{x.value.map(y=>(
|
||||
<Box className={classes.commitable} key={y.path}>
|
||||
<Box /*className={classes.commitable}*/ key={y.path}>
|
||||
<Button variant="contained" onClick={()=>{
|
||||
set_disable(true);
|
||||
prop.onCommit(y);
|
||||
@ -59,7 +59,7 @@ function TypeDifference(prop:{
|
||||
|
||||
export function DifferencePage(){
|
||||
const ctx = useContext(UserContext);
|
||||
const classes = useStyles();
|
||||
//const classes = useStyles();
|
||||
const [diffList,setDiffList] = useState<
|
||||
FileDifference[]
|
||||
>([]);
|
||||
|
@ -1,22 +1,13 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { Headline, CommonMenuList,LoadingCircle, ContentInfo, NavList, NavItem, TagChip } from '../component/mod';
|
||||
|
||||
import { Box, Paper, Link, useMediaQuery, Portal, List, ListItem, ListItemIcon, Tooltip, ListItemText, Typography, Chip } from '@material-ui/core';
|
||||
import {useTheme, makeStyles, Theme} from '@material-ui/core/styles';
|
||||
import { Box, Typography, Chip } from '@mui/material';
|
||||
import ContentAccessor,{QueryListOption, Document} from '../accessor/document';
|
||||
import {Link as RouterLink} from 'react-router-dom';
|
||||
import {toQueryString} from '../accessor/util';
|
||||
|
||||
import {useLocation} from 'react-router-dom';
|
||||
import { QueryStringToMap } from '../accessor/util';
|
||||
|
||||
const useStyles = makeStyles((theme:Theme)=>({
|
||||
root:{
|
||||
display:"grid",
|
||||
gridGap: theme.spacing(4),
|
||||
},
|
||||
}));
|
||||
|
||||
export type GalleryProp = {
|
||||
option?:QueryListOption;
|
||||
diff:string;
|
||||
@ -28,6 +19,7 @@ type GalleryState = {
|
||||
export const GalleryInfo = (props: GalleryProp)=>{
|
||||
const [state,setState]= useState<GalleryState>({documents:undefined});
|
||||
useEffect(()=>{
|
||||
const abortController = new AbortController();
|
||||
const load = (async ()=>{
|
||||
const c = await ContentAccessor.findList(props.option);
|
||||
//todo : if c is undefined, retry to fetch 3 times. and show error message.
|
||||
@ -35,14 +27,15 @@ export const GalleryInfo = (props: GalleryProp)=>{
|
||||
})
|
||||
load();
|
||||
},[props.diff]);
|
||||
const classes = useStyles();
|
||||
const queryString = toQueryString(props.option??{});
|
||||
|
||||
if(state.documents === undefined){
|
||||
return (<LoadingCircle/>);
|
||||
}
|
||||
else{
|
||||
return (<Box className={classes.root}>
|
||||
return (<Box sx={{
|
||||
display:'grid'
|
||||
}}>
|
||||
{props.option !== undefined && props.diff !== "" && <Box>
|
||||
<Typography variant="h6">search for</Typography>
|
||||
{props.option.word !== undefined && <Chip label={"search : "+props.option.word}></Chip>}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {CommonMenuList, Headline} from '../component/mod';
|
||||
import { Button, Dialog, DialogActions, DialogContent, DialogContentText,
|
||||
DialogTitle, MenuList, Paper, TextField, Typography, useTheme } from '@material-ui/core';
|
||||
DialogTitle, MenuList, Paper, TextField, Typography, useTheme } from '@mui/material';
|
||||
import { UserContext } from '../state';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {doLogin as doSessionLogin} from '../state';
|
||||
|
||||
export const LoginPage = ()=>{
|
||||
@ -11,7 +11,7 @@ export const LoginPage = ()=>{
|
||||
const [userLoginInfo,setUserLoginInfo]= useState({username:"",password:""});
|
||||
const [openDialog,setOpenDialog] = useState({open:false,message:""});
|
||||
const {setUsername,setPermission} = useContext(UserContext);
|
||||
const history = useHistory();
|
||||
const navigate = useNavigate();
|
||||
const handleDialogClose = ()=>{
|
||||
setOpenDialog({...openDialog,open:false});
|
||||
}
|
||||
@ -34,7 +34,7 @@ export const LoginPage = ()=>{
|
||||
else console.error(e);
|
||||
return;
|
||||
}
|
||||
history.push("/");
|
||||
navigate("/");
|
||||
}
|
||||
const menu = CommonMenuList();
|
||||
return <Headline menu={menu}>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { CommonMenuList, Headline } from "../component/mod";
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { UserContext } from "../state";
|
||||
import { Chip, Grid, makeStyles, Paper, Theme, Typography, Divider, Button,
|
||||
Dialog, DialogTitle, DialogContentText, DialogContent, TextField, DialogActions } from "@material-ui/core";
|
||||
import { Chip, Grid, Paper, Theme, Typography, Divider, Button,
|
||||
Dialog, DialogTitle, DialogContentText, DialogContent, TextField, DialogActions } from "@mui/material";
|
||||
|
||||
const useStyles = makeStyles((theme:Theme)=>({
|
||||
const useStyles = ((theme:Theme)=>({
|
||||
paper:{
|
||||
alignSelf:"center",
|
||||
padding:theme.spacing(2),
|
||||
@ -17,7 +17,7 @@ const useStyles = makeStyles((theme:Theme)=>({
|
||||
|
||||
export function ProfilePage(){
|
||||
const userctx = useContext(UserContext);
|
||||
const classes = useStyles();
|
||||
//const classes = useStyles();
|
||||
const menu = CommonMenuList();
|
||||
const [pw_open,set_pw_open] = useState(false);
|
||||
const [oldpw,setOldpw] = useState("");
|
||||
@ -66,7 +66,7 @@ export function ProfilePage(){
|
||||
handle_close();
|
||||
}
|
||||
return (<Headline menu={menu}>
|
||||
<Paper className={classes.paper}>
|
||||
<Paper /*className={classes.paper}*/>
|
||||
<Grid container direction="column" alignItems="center">
|
||||
<Grid item>
|
||||
<Typography variant='h4'>{userctx.username}</Typography>
|
||||
@ -87,7 +87,7 @@ export function ProfilePage(){
|
||||
<DialogTitle>Password Reset</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography>type the old and new password</Typography>
|
||||
<div className={classes.formfield}>
|
||||
<div /*className={classes.formfield}*/>
|
||||
{(!isElectronContent) && (<TextField autoFocus margin='dense' type="password" label="old password"
|
||||
value={oldpw} onChange={(e)=>setOldpw(e.target.value)}></TextField>)}
|
||||
<TextField margin='dense' type="password" label="new password"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import { Typography, useTheme } from '@material-ui/core';
|
||||
import { Typography, useTheme } from '@mui/material';
|
||||
import { Document } from '../../accessor/document';
|
||||
|
||||
type ComicType = "comic"|"artist cg"|"donjinshi"|"western"
|
||||
@ -14,7 +14,6 @@ export type PresentableTag = {
|
||||
}
|
||||
|
||||
export const ComicReader = (props:{doc:Document})=>{
|
||||
const theme = useTheme();
|
||||
const additional = props.doc.additional;
|
||||
const [curPage,setCurPage] = useState(0);
|
||||
if(!('page' in additional)){
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Typography } from '@material-ui/core';
|
||||
import { Typography } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { Document, makeThumbnailUrl } from '../../accessor/document';
|
||||
import {ComicReader} from './comic';
|
||||
@ -22,10 +22,10 @@ export const getPresenter = (content:Document):PagePresenter => {
|
||||
return ()=><Typography variant='h2'>Not implemented reader</Typography>;
|
||||
}
|
||||
|
||||
export const ThumbnailContainer = (props:{content:Document, className?:string})=>{
|
||||
export const ThumbnailContainer = (props:{content:Document, className?:string, style?:React.CSSProperties})=>{
|
||||
const thumbnailurl = makeThumbnailUrl(props.content);
|
||||
if(props.content.content_type === "video"){
|
||||
return (<video src={thumbnailurl} muted autoPlay loop className={props.className}></video>)
|
||||
return (<video src={thumbnailurl} muted autoPlay loop className={props.className} style={props.style}></video>)
|
||||
}
|
||||
else return (<img src={thumbnailurl} className={props.className}></img>)
|
||||
else return (<img src={thumbnailurl} className={props.className} style={props.style}></img>)
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import {Typography, Paper} from '@material-ui/core';
|
||||
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
||||
import {Typography, Paper} from '@mui/material';
|
||||
import {ArrowBack as ArrowBackIcon} from '@mui/icons-material';
|
||||
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
||||
|
||||
export const SettingPage = ()=>{
|
||||
|
@ -1,70 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "ESNext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./build", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
"noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
"isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
const path = require("path");
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
|
||||
module.exports = ()=>{return {
|
||||
entry: './app.tsx',
|
||||
output: {
|
||||
path: path.resolve(__dirname, '../../dist/js'),
|
||||
filename: 'bundle.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|ts|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
babelrc: true,//why babelrc not working? why is webpack not reading '.babelrc'?
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-typescript',
|
||||
'@babel/preset-react'
|
||||
],
|
||||
plugins: [
|
||||
'@babel/proposal-class-properties',
|
||||
'@babel/proposal-object-rest-spread'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [MiniCssExtractPlugin.loader,'css-loader']
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins : [
|
||||
new MiniCssExtractPlugin({
|
||||
"filename":'../css/style.css'}),
|
||||
],
|
||||
devtool: 'source-map',
|
||||
resolve: {
|
||||
extensions: ['.js','.css','.ts','.tsx']
|
||||
}
|
||||
};}
|
13
src/search/indexer.ts
Normal file
13
src/search/indexer.ts
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
export interface PaginationOption{
|
||||
cursor:number;
|
||||
limit:number;
|
||||
}
|
||||
|
||||
export interface IIndexer{
|
||||
indexDoc(word:string,doc_id:number):boolean;
|
||||
indexDoc(word:string[],doc_id:number):boolean;
|
||||
|
||||
getDoc(word:string,option?:PaginationOption):number[];
|
||||
getDoc(word:string[],option?:PaginationOption):number[];
|
||||
}
|
10
src/search/tokenizer.ts
Normal file
10
src/search/tokenizer.ts
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
export interface ITokenizer{
|
||||
tokenize(s:string):string[];
|
||||
}
|
||||
|
||||
export class DefaultTokenizer implements ITokenizer{
|
||||
tokenize(s: string): string[] {
|
||||
return s.split(" ");
|
||||
}
|
||||
}
|
@ -119,10 +119,12 @@ class ServerApplication{
|
||||
}
|
||||
})};
|
||||
const setting = get_setting();
|
||||
static_file_server('dist/css/style.css','css');
|
||||
static_file_server('dist/js/bundle.js','js');
|
||||
if(setting.mode === "development")
|
||||
static_file_server('dist/js/bundle.js.map','text');
|
||||
static_file_server('dist/bundle.css','css');
|
||||
static_file_server('dist/bundle.js','js');
|
||||
if(setting.mode === "development"){
|
||||
static_file_server('dist/bundle.js.map','text');
|
||||
static_file_server('dist/bundle.css.map','text');
|
||||
}
|
||||
}
|
||||
start_server(){
|
||||
let setting = get_setting();
|
||||
|
Loading…
Reference in New Issue
Block a user