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;
|
<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">
|
font-src 'self' fonts.gstatic.com">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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" />
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script src="/dist/js/bundle.js"></script>
|
<script src="/dist/bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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{
|
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[]>{
|
async findByPath(basepath: string, filename?: string): Promise<Document[]>{
|
||||||
throw new Error("not allowed");
|
throw new Error("not allowed");
|
||||||
};
|
};
|
||||||
|
@ -1,46 +1,50 @@
|
|||||||
import React, { createContext, useEffect, useRef, useState } from 'react';
|
import React, { createContext, useEffect, useRef, useState } from 'react';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import {BrowserRouter, Redirect, Route, Switch as RouterSwitch} from 'react-router-dom';
|
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import { Gallery, DocumentAbout, LoginPage, NotFoundPage, ProfilePage,DifferencePage, SettingPage} from './page/mod';
|
import { Gallery, DocumentAbout, LoginPage, NotFoundPage, ProfilePage, DifferencePage, SettingPage } from './page/mod';
|
||||||
import {getInitialValue, UserContext} from './state';
|
import { getInitialValue, UserContext } from './state';
|
||||||
|
import { ThemeProvider, createTheme } from '@mui/material';
|
||||||
|
|
||||||
import './css/style.css';
|
import './css/style.css';
|
||||||
|
|
||||||
|
const theme = createTheme();
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [user,setUser] = useState("");
|
const [user, setUser] = useState("");
|
||||||
const [userPermission,setUserPermission] = useState<string[]>([]);
|
const [userPermission, setUserPermission] = useState<string[]>([]);
|
||||||
(async ()=>{
|
(async () => {
|
||||||
const {username,permission} = await getInitialValue();
|
const { username, permission } = await getInitialValue();
|
||||||
if(username !== user){
|
if (username !== user) {
|
||||||
setUser(username);
|
setUser(username);
|
||||||
setUserPermission(permission);
|
setUserPermission(permission);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
//useEffect(()=>{});
|
//useEffect(()=>{});
|
||||||
return (
|
return (
|
||||||
<UserContext.Provider value={{
|
<UserContext.Provider value={{
|
||||||
username:user,
|
username: user,
|
||||||
setUsername:setUser,
|
setUsername: setUser,
|
||||||
permission:userPermission,
|
permission: userPermission,
|
||||||
setPermission:setUserPermission}}>
|
setPermission: setUserPermission
|
||||||
<BrowserRouter>
|
}}>
|
||||||
<RouterSwitch>
|
<ThemeProvider theme={theme}>
|
||||||
<Route path="/" exact render={()=><Redirect to='/search?'/>}></Route>
|
<BrowserRouter>
|
||||||
<Route path="/search" render={()=><Gallery />}></Route>
|
<Routes>
|
||||||
<Route path="/doc" render={(prop)=><DocumentAbout {...prop}/>}></Route>
|
<Route path="/" element={<Navigate replace to='/search?' />} />
|
||||||
<Route path="/login" render={()=><LoginPage></LoginPage>}/>
|
<Route path="/search" element={<Gallery />} />
|
||||||
<Route path="/profile" component={ProfilePage}></Route>
|
<Route path="/doc" element={<DocumentAbout />}></Route>
|
||||||
<Route path="/difference" component={DifferencePage}></Route>
|
<Route path="/login" element={<LoginPage></LoginPage>} />
|
||||||
<Route path="/setting" component={SettingPage}></Route>
|
<Route path="/profile" element={<ProfilePage />}></Route>
|
||||||
<Route>
|
<Route path="/difference" element={<DifferencePage />}></Route>
|
||||||
<NotFoundPage/>
|
<Route path="/setting" element={<SettingPage />}></Route>
|
||||||
</Route>
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
</RouterSwitch>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</UserContext.Provider>);
|
</ThemeProvider>
|
||||||
|
</UserContext.Provider>);
|
||||||
};
|
};
|
||||||
|
|
||||||
ReactDom.render(
|
ReactDom.render(
|
||||||
<App/>,
|
<App />,
|
||||||
document.getElementById("root")
|
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 React, { } from 'react';
|
||||||
import { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink } from 'react-router-dom';
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
import { Document } from '../accessor/document';
|
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 { ThumbnailContainer } from '../page/reader/reader';
|
||||||
import { TagChip } from '../component/tagchip';
|
import { TagChip } from '../component/tagchip';
|
||||||
import { ComicReader } from '../page/reader/comic';
|
|
||||||
|
|
||||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||||
export const makeContentReaderUrl = (id: number) => `/doc/${id}/reader`;
|
export const makeContentReaderUrl = (id: number) => `/doc/${id}/reader`;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const useStyles = ((theme: Theme) => ({
|
||||||
root: {
|
|
||||||
display: "flex",
|
|
||||||
[theme.breakpoints.down("sm")]: {
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
thumbnail_content: {
|
thumbnail_content: {
|
||||||
maxHeight: '400px',
|
maxHeight: '400px',
|
||||||
maxWidth: 'min(400px, 100vw)',
|
maxWidth: 'min(400px, 100vw)',
|
||||||
@ -43,26 +36,26 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||||||
overflowY: 'hidden',
|
overflowY: 'hidden',
|
||||||
alignItems: 'baseline',
|
alignItems: 'baseline',
|
||||||
},
|
},
|
||||||
short_subinfoContainer:{
|
short_subinfoContainer: {
|
||||||
[theme.breakpoints.down("md")]:{
|
[theme.breakpoints.down("md")]: {
|
||||||
display:'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
short_root:{
|
short_root: {
|
||||||
overflowY:'hidden',
|
overflowY: 'hidden',
|
||||||
display:'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
[theme.breakpoints.up("sm")]:{
|
[theme.breakpoints.up("sm")]: {
|
||||||
height:200,
|
height: 200,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
short_thumbnail_anchor:{
|
short_thumbnail_anchor: {
|
||||||
background: '#272733',
|
background: '#272733',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
[theme.breakpoints.up("sm")]:{
|
[theme.breakpoints.up("sm")]: {
|
||||||
width: theme.spacing(25),
|
width: theme.spacing(25),
|
||||||
height: theme.spacing(25),
|
height: theme.spacing(25),
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
@ -84,66 +77,75 @@ export const ContentInfo = (props: {
|
|||||||
infoContainer?: string,
|
infoContainer?: string,
|
||||||
subinfoContainer?: string
|
subinfoContainer?: string
|
||||||
},
|
},
|
||||||
gallery?:string,
|
gallery?: string,
|
||||||
short?:boolean
|
short?: boolean
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
//const classes = useStyles();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const document = props.document;
|
const document = props.document;
|
||||||
const propclasses = props.classes ?? {};
|
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_anchor = props.short ? classes.short_thumbnail_anchor : "";
|
||||||
const thumbnail_content = props.short ? classes.short_thumbnail_content :
|
const thumbnail_content = props.short ? classes.short_thumbnail_content :
|
||||||
classes.thumbnail_content;
|
classes.thumbnail_content;
|
||||||
const subinfoContainer = props.short ? classes.short_subinfoContainer :
|
const subinfoContainer = props.short ? classes.short_subinfoContainer :
|
||||||
classes.subinfoContainer;
|
classes.subinfoContainer;*/
|
||||||
return (<Paper className={propclasses.root ?? rootName} elevation={4}>
|
const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id);
|
||||||
<Link className={propclasses.thumbnail_anchor ?? thumbnail_anchor} component={RouterLink} to={{
|
return (<Paper sx={{
|
||||||
pathname:makeContentReaderUrl(document.id)
|
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 ?
|
{document.deleted_at === null ?
|
||||||
(<ThumbnailContainer content={document}
|
(<ThumbnailContainer content={document}
|
||||||
className={propclasses.thumbnail_content ?? thumbnail_content}/>)
|
style={{
|
||||||
: (<Typography className={propclasses.thumbnail_content ?? thumbnail_content} variant='h4'>Deleted</Typography>)}
|
maxHeight: '400px',
|
||||||
|
maxWidth: 'min(400px, 100vw)',
|
||||||
|
}}/>)
|
||||||
|
: (<Typography/* className={propclasses.thumbnail_content ?? thumbnail_content} */ variant='h4'>Deleted</Typography>)}
|
||||||
</Link>
|
</Link>
|
||||||
<Box className={propclasses.infoContainer ?? classes.infoContainer}>
|
<Box /*className={propclasses.infoContainer ?? classes.infoContainer}*/>
|
||||||
<Link variant='h5' color='inherit' component={RouterLink} to={{
|
<Link variant='h5' color='inherit' component={RouterLink} to={{pathname: url}}
|
||||||
pathname: props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id),
|
/*className={propclasses.title ?? classes.title}*/>
|
||||||
}}
|
|
||||||
className={propclasses.title ?? classes.title}>
|
|
||||||
{document.title}
|
{document.title}
|
||||||
</Link>
|
</Link>
|
||||||
<Box className={propclasses.subinfoContainer ?? subinfoContainer}>
|
<Box /*className={propclasses.subinfoContainer ?? subinfoContainer}*/>
|
||||||
{props.short ? (<Box className={propclasses.tag_list ?? classes.tag_list}>{document.tags.map(x =>
|
{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>)
|
(<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>)
|
||||||
)}</Box>) : (
|
)}</Box>) : (
|
||||||
<ComicDetailTag tags={document.tags} classes={({tag_list:classes.tag_list})}></ComicDetailTag>)
|
<ComicDetailTag tags={document.tags}/* classes={({tag_list:classes.tag_list})}*/ ></ComicDetailTag>)
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Paper>);
|
</Paper>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ComicDetailTag(prop:{tags:string[],classes:{
|
function ComicDetailTag(prop: {
|
||||||
|
tags: string[]/*classes:{
|
||||||
tag_list:string
|
tag_list:string
|
||||||
}}){
|
}*/}) {
|
||||||
let allTag = prop.tags;
|
let allTag = prop.tags;
|
||||||
const tagKind = ["artist","group","series","type","character"];
|
const tagKind = ["artist", "group", "series", "type", "character"];
|
||||||
let tagTable:{[kind:string]:string[]} = {};
|
let tagTable: { [kind: string]: string[] } = {};
|
||||||
for(const kind of tagKind){
|
for (const kind of tagKind) {
|
||||||
const tags = allTag.filter(x => x.startsWith(kind+":")).map(x => x.slice(kind.length+1));
|
const tags = allTag.filter(x => x.startsWith(kind + ":")).map(x => x.slice(kind.length + 1));
|
||||||
tagTable[kind] = tags;
|
tagTable[kind] = tags;
|
||||||
allTag = allTag.filter(x => !x.startsWith(kind+":"));
|
allTag = allTag.filter(x => !x.startsWith(kind + ":"));
|
||||||
}
|
}
|
||||||
return (<React.Fragment>
|
return (<React.Fragment>
|
||||||
{tagKind.map(key=>(
|
{tagKind.map(key => (
|
||||||
<React.Fragment key={key}>
|
<React.Fragment key={key}>
|
||||||
<Typography variant='subtitle1'>{key}</Typography>
|
<Typography variant='subtitle1'>{key}</Typography>
|
||||||
<Box>{tagTable[key].length !== 0 ? tagTable[key].join(", ") : "N/A"}</Box>
|
<Box>{tagTable[key].length !== 0 ? tagTable[key].join(", ") : "N/A"}</Box>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
<Typography variant='subtitle1'>Tags</Typography>
|
<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>))}
|
{allTag.map(x => (<TagChip key={x} label={x} clickable tagname={x} size="small"></TagChip>))}
|
||||||
</Box>
|
</Box>
|
||||||
</React.Fragment>);
|
</React.Fragment>);
|
||||||
|
@ -1,123 +1,77 @@
|
|||||||
import ReactDom from 'react-dom';
|
import React, { useContext, useState } from 'react';
|
||||||
import React, { ReactNode, useContext, useState } from 'react';
|
|
||||||
import {
|
import {
|
||||||
Button, CssBaseline, Divider, IconButton, List, ListItem, Drawer,
|
Button, CssBaseline, Divider, IconButton, List, ListItem, Drawer,
|
||||||
AppBar, Toolbar, Typography, InputBase, ListItemIcon, ListItemText, Menu, MenuItem,
|
AppBar, Toolbar, Typography, InputBase, ListItemIcon, ListItemText, Menu, MenuItem,
|
||||||
Hidden, Tooltip, Link
|
Hidden, Tooltip, Link, styled
|
||||||
} from '@material-ui/core';
|
} from '@mui/material';
|
||||||
import { makeStyles, Theme, useTheme, fade } from '@material-ui/core/styles';
|
import { alpha, Theme, useTheme } from '@mui/material/styles';
|
||||||
import { ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle
|
import {
|
||||||
} from '@material-ui/icons';
|
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';
|
import { doLogout, UserContext } from '../state';
|
||||||
|
|
||||||
const drawerWidth = 240;
|
const drawerWidth = 270;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||||
root: {
|
...theme.mixins.toolbar
|
||||||
display: 'flex'
|
}));
|
||||||
|
|
||||||
|
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'], {
|
const StyledSearchBar = styled('div')(({ theme }) => ({
|
||||||
easing: theme.transitions.easing.sharp,
|
position: 'relative',
|
||||||
duration: theme.transitions.duration.leavingScreen
|
borderRadius: theme.shape.borderRadius,
|
||||||
})
|
backgroundColor: alpha(theme.palette.common.white, 0.15),
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: alpha(theme.palette.common.white, 0.25),
|
||||||
},
|
},
|
||||||
menuButton: {
|
marginLeft: 0,
|
||||||
marginRight: 36
|
width: '100%',
|
||||||
|
[theme.breakpoints.up('sm')]: {
|
||||||
|
marginLeft: theme.spacing(1),
|
||||||
|
width: 'auto',
|
||||||
},
|
},
|
||||||
hide: {
|
}));
|
||||||
display: "none"
|
const StyledInputBase = styled(InputBase)(({ theme }) => ({
|
||||||
},
|
color: 'inherit',
|
||||||
drawer: {
|
'& .MuiInputBase-input': {
|
||||||
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: {
|
|
||||||
padding: theme.spacing(1, 1, 1, 0),
|
padding: theme.spacing(1, 1, 1, 0),
|
||||||
// vertical padding + font size from searchIcon
|
// vertical padding + font size from searchIcon
|
||||||
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
|
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
||||||
transition: theme.transitions.create('width'),
|
transition: theme.transitions.create('width'),
|
||||||
width: '100%',
|
width: '100%',
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('sm')]: {
|
||||||
width: '20ch',
|
width: '12ch',
|
||||||
"&:hover": {
|
'&:focus': {
|
||||||
width: '25ch'
|
width: '20ch',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
grow: {
|
|
||||||
flexGrow: 1,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const closedMixin = (theme: Theme) => ({
|
||||||
|
overflowX: 'hidden',
|
||||||
|
width: `calc(${theme.spacing(7)} + 1px)`,
|
||||||
|
});
|
||||||
|
|
||||||
export const Headline = (prop: {
|
export const Headline = (prop: {
|
||||||
children?: React.ReactNode,
|
children?: React.ReactNode,
|
||||||
classes?:{
|
classes?: {
|
||||||
content?:string,
|
content?: string,
|
||||||
toolbar?:string,
|
toolbar?: string,
|
||||||
},
|
},
|
||||||
menu: React.ReactNode
|
menu: React.ReactNode
|
||||||
}) => {
|
}) => {
|
||||||
const [v, setv] = useState(false);
|
const [v, setv] = useState(false);
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const classes = useStyles();
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const toggleV = () => setv(!v);
|
const toggleV = () => setv(!v);
|
||||||
const handleProfileMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
|
const handleProfileMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
|
||||||
@ -137,39 +91,58 @@ export const Headline = (prop: {
|
|||||||
onClose={handleProfileMenuClose}
|
onClose={handleProfileMenuClose}
|
||||||
>
|
>
|
||||||
<MenuItem component={RouterLink} to='/profile'>Profile</MenuItem>
|
<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>);
|
</Menu>);
|
||||||
const drawer_contents = (<>
|
const drawer_contents = (<>
|
||||||
<div className={classes.toolbar}>
|
<DrawerHeader>
|
||||||
<IconButton onClick={toggleV}>
|
<IconButton onClick={toggleV}>
|
||||||
{theme.direction === "ltr" ? <ChevronLeft /> : <ChevronRight />}
|
{theme.direction === "ltr" ? <ChevronLeft /> : <ChevronRight />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</DrawerHeader>
|
||||||
<Divider />
|
<Divider />
|
||||||
{prop.menu}
|
{prop.menu}
|
||||||
</>);
|
</>);
|
||||||
return (<div className={classes.root}>
|
return (<div style={{ display: 'flex' }}>
|
||||||
<CssBaseline />
|
<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>
|
<Toolbar>
|
||||||
<IconButton color="inherit"
|
<IconButton color="inherit"
|
||||||
aria-label="open drawer"
|
aria-label="open drawer"
|
||||||
onClick={toggleV}
|
onClick={toggleV}
|
||||||
edge="start"
|
edge="start"
|
||||||
className={classes.menuButton}>
|
style={{ marginRight: 36 }}
|
||||||
|
>
|
||||||
<MenuIcon></MenuIcon>
|
<MenuIcon></MenuIcon>
|
||||||
</IconButton>
|
</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
|
Ionian
|
||||||
</Link>
|
</Link>
|
||||||
<div className={classes.grow}></div>
|
<div style={{ flexGrow: 1 }}></div>
|
||||||
<div className={classes.search}>
|
<StyledSearchBar >
|
||||||
<div className={classes.searchIcon}>
|
<div style={{
|
||||||
|
padding: theme.spacing(0, 2),
|
||||||
|
height: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
</div>
|
</div>
|
||||||
<InputBase placeholder="search"
|
<StyledInputBase placeholder="search"></StyledInputBase>
|
||||||
classes={{ root: classes.inputRoot, input: classes.inputInput }}></InputBase>
|
</StyledSearchBar>
|
||||||
</div>
|
|
||||||
{
|
{
|
||||||
isLogin ?
|
isLogin ?
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -188,21 +161,35 @@ export const Headline = (prop: {
|
|||||||
{renderProfileMenu}
|
{renderProfileMenu}
|
||||||
<nav>
|
<nav>
|
||||||
<Hidden smUp implementation="css">
|
<Hidden smUp implementation="css">
|
||||||
<Drawer variant="temporary" anchor='left' open={v} onClose={toggleV}
|
<StyledDrawer variant="temporary" anchor='left' open={v} onClose={toggleV}
|
||||||
classes={{ paper: classes.drawerPaper }}>
|
sx={{
|
||||||
|
width: drawerWidth
|
||||||
|
}}
|
||||||
|
>
|
||||||
{drawer_contents}
|
{drawer_contents}
|
||||||
</Drawer>
|
</StyledDrawer>
|
||||||
</Hidden>
|
</Hidden>
|
||||||
<Hidden xsDown implementation="css">
|
<Hidden xsDown implementation="css">
|
||||||
<Drawer variant='permanent' anchor='left' className={[classes.drawer, classes.drawerClose].join(" ").trim()} classes={{
|
<StyledDrawer variant='permanent' anchor='left'
|
||||||
paper: classes.drawerClose
|
sx={{
|
||||||
}}>
|
overflowX: 'hidden',
|
||||||
|
width: theme.spacing(7) + 1,
|
||||||
|
...closedMixin(theme),
|
||||||
|
'& .MuiDrawer-paper': closedMixin(theme),
|
||||||
|
}}>
|
||||||
{drawer_contents}
|
{drawer_contents}
|
||||||
</Drawer>
|
</StyledDrawer>
|
||||||
</Hidden>
|
</Hidden>
|
||||||
</nav>
|
</nav>
|
||||||
<main className={prop.classes?.content ?? classes.content}>
|
<main style={{
|
||||||
<div className={prop.classes?.toolbar ?? classes.toolbar}></div>
|
display: 'flex',
|
||||||
|
flexFlow: 'column',
|
||||||
|
flexGrow: 1,
|
||||||
|
padding: theme.spacing(3),
|
||||||
|
marginTop: theme.spacing(8),
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
}} ></div>
|
||||||
{prop.children}
|
{prop.children}
|
||||||
</main>
|
</main>
|
||||||
</div>);
|
</div>);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Box, CircularProgress} from '@material-ui/core';
|
import {Box, CircularProgress} from '@mui/material';
|
||||||
|
|
||||||
export const LoadingCircle = ()=>{
|
export const LoadingCircle = ()=>{
|
||||||
return (<Box style={{alignSelf:'center'}}>
|
return (<Box style={{alignSelf:'center'}}>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import React from 'react';
|
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,
|
import {ArrowBack as ArrowBackIcon, Settings as SettingIcon,
|
||||||
Collections as CollectionIcon, VideoLibrary as VideoIcon, Home as HomeIcon,
|
Collections as CollectionIcon, VideoLibrary as VideoIcon, Home as HomeIcon,
|
||||||
Folder as FolderIcon } from '@material-ui/icons';
|
Folder as FolderIcon } from '@mui/icons-material';
|
||||||
import {Link as RouterLink, useHistory} from 'react-router-dom';
|
import {Link as RouterLink} from 'react-router-dom';
|
||||||
|
|
||||||
export const NavItem = (props:{name:string,to:string, icon:React.ReactElement<any,any>})=>{
|
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}>
|
return (<ListItem button key={props.name} component={RouterLink} to={props.to}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Tooltip title={props.name.toLocaleLowerCase()} placement="bottom">
|
<Tooltip title={props.name.toLocaleLowerCase()} placement="bottom">
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {ChipTypeMap} from '@material-ui/core/Chip';
|
import {ChipTypeMap} from '@mui/material/Chip';
|
||||||
import { Chip, colors } from '@material-ui/core';
|
import { Chip, colors } from '@mui/material';
|
||||||
import {useTheme, makeStyles, Theme, emphasize, fade} from '@material-ui/core/styles';
|
import { Theme, emphasize} from '@mui/material/styles';
|
||||||
import {Link as RouterLink} from 'react-router-dom';
|
import {Link as RouterLink} from 'react-router-dom';
|
||||||
|
|
||||||
type TagChipStyleProp = {
|
type TagChipStyleProp = {
|
||||||
color: string
|
color: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const useTagStyles = makeStyles((theme:Theme)=>({
|
const useTagStyles = ((theme:Theme)=>({
|
||||||
root:(props:TagChipStyleProp)=>({
|
root:(props:TagChipStyleProp)=>({
|
||||||
color: theme.palette.getContrastText(props.color),
|
color: theme.palette.getContrastText(props.color),
|
||||||
backgroundColor: props.color,
|
backgroundColor: props.color,
|
||||||
@ -27,14 +27,14 @@ const useTagStyles = makeStyles((theme:Theme)=>({
|
|||||||
color: (props:TagChipStyleProp)=>props.color,
|
color: (props:TagChipStyleProp)=>props.color,
|
||||||
border: (props:TagChipStyleProp)=> `1px solid ${props.color}`,
|
border: (props:TagChipStyleProp)=> `1px solid ${props.color}`,
|
||||||
'$clickable&:hover, $clickable&:focus, $deletable&:focus': {
|
'$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:{
|
icon:{
|
||||||
color:"inherit",
|
color:"inherit",
|
||||||
},
|
},
|
||||||
deleteIcon:{
|
deleteIcon:{
|
||||||
color:(props:TagChipStyleProp)=>fade(theme.palette.getContrastText(props.color),0.7),
|
//color:(props:TagChipStyleProp)=> (theme.palette.getContrastText(props.color),0.7),
|
||||||
"&:hover, &:active":{
|
"&:hover, &:active":{
|
||||||
color:(props:TagChipStyleProp)=>theme.palette.getContrastText(props.color),
|
color:(props:TagChipStyleProp)=>theme.palette.getContrastText(props.color),
|
||||||
}
|
}
|
||||||
@ -59,10 +59,8 @@ type ColorChipProp = Omit<ChipTypeMap['props'],"color"> & TagChipStyleProp & {
|
|||||||
|
|
||||||
export const ColorChip = (props:ColorChipProp)=>{
|
export const ColorChip = (props:ColorChipProp)=>{
|
||||||
const {color,...rest} = props;
|
const {color,...rest} = props;
|
||||||
const classes = useTagStyles({color : color !== "default" ? color : "#000"});
|
//const classes = useTagStyles({color : color !== "default" ? color : "#000"});
|
||||||
return <Chip color="default" classes={{
|
return <Chip color="default" {...rest}></Chip>;
|
||||||
...(color !== "default" ? classes : {})
|
|
||||||
}} {...rest}></Chip>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagChipProp = Omit<ChipTypeMap['props'],"color"> & {
|
type TagChipProp = Omit<ChipTypeMap['props'],"color"> & {
|
||||||
|
@ -1,52 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "ionian-client",
|
"name": "ionian_client",
|
||||||
"version": "1.0.0",
|
"version": "0.0.1",
|
||||||
"description": "",
|
"description": "client of ionian",
|
||||||
"main": "index.js",
|
"dependencies": {
|
||||||
"scripts": {
|
"@emotion/react": "^11.9.0",
|
||||||
"build:dev": "webpack --mode development",
|
"@emotion/styled": "^11.8.1",
|
||||||
"build:prod": "webpack --mode production",
|
"@mui/icons-material": "^5.6.2",
|
||||||
"build:watch": "webpack --mode development -w",
|
"@mui/material": "^5.6.2",
|
||||||
"type-check": "tsc --noEmit"
|
"@types/react": "^18.0.5",
|
||||||
},
|
"@types/react-dom": "^18.0.1",
|
||||||
"author": "",
|
"react": "^18.0.0",
|
||||||
"license": "ISC",
|
"react-dom": "^18.0.0",
|
||||||
"browserslist": {
|
"react-router-dom": "^6.3.0"
|
||||||
"production": [
|
},
|
||||||
"> 10%"
|
"devDependencies": {
|
||||||
],
|
"esbuild": "^0.14.36",
|
||||||
"development": [
|
"ts-node": "^10.7.0"
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Typography} from '@material-ui/core';
|
import {Typography} from '@mui/material';
|
||||||
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
import {ArrowBack as ArrowBackIcon} from '@mui/icons-material';
|
||||||
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
||||||
|
|
||||||
export const NotFoundPage = ()=>{
|
export const NotFoundPage = ()=>{
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import React, { useState, useEffect, useContext } from 'react';
|
import React, { useState, useEffect} from 'react';
|
||||||
import { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink, useParams, useLocation } from 'react-router-dom';
|
import { Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||||||
import DocumentAccessor, { Document } from '../accessor/document';
|
import DocumentAccessor, { Document } from '../accessor/document';
|
||||||
import { LoadingCircle } from '../component/loading';
|
import { LoadingCircle } from '../component/loading';
|
||||||
import { Link, Paper, makeStyles, Theme, Box, useTheme, Typography } from '@material-ui/core';
|
import { Theme, Typography } from '@mui/material';
|
||||||
import {ArrowBack as ArrowBackIcon } from '@material-ui/icons';
|
|
||||||
import { getPresenter } from './reader/reader';
|
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';
|
import {NotFoundPage} from './404';
|
||||||
|
|
||||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||||
@ -16,7 +15,7 @@ type DocumentState = {
|
|||||||
notfound: boolean,
|
notfound: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles((theme:Theme)=>({
|
const styles = ((theme:Theme)=>({
|
||||||
noPaddingContent:{
|
noPaddingContent:{
|
||||||
display:'flex',
|
display:'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -28,12 +27,13 @@ const useStyles = makeStyles((theme:Theme)=>({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const DocumentAbout = (prop: { match: MatchType }) => {
|
export const DocumentAbout = (prop?: {}) => {
|
||||||
const match = useRouteMatch<{id:string}>("/doc/:id");
|
const location = useLocation();
|
||||||
|
const match = useParams<{id:string}>();
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
throw new Error("unreachable");
|
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 [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound:false });
|
||||||
const menu_list = (link?:string) => <CommonMenuList url={link}></CommonMenuList>;
|
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)) {
|
if (isNaN(id)) {
|
||||||
return (
|
return (
|
||||||
<Headline menu={menu_list()}>
|
<Headline menu={menu_list()}>
|
||||||
@ -68,23 +68,20 @@ export const DocumentAbout = (prop: { match: MatchType }) => {
|
|||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
const ReaderPage = getPresenter(info.doc);
|
const ReaderPage = getPresenter(info.doc);
|
||||||
return (<Switch>
|
return (<Routes>
|
||||||
<Route exact path={`${prop.match.path}/:id`}>
|
<Route path={`:id`}>
|
||||||
<Headline menu={menu_list()}>
|
<Headline menu={menu_list()}>
|
||||||
<ContentInfo document={info.doc}></ContentInfo>
|
<ContentInfo document={info.doc}></ContentInfo>
|
||||||
</Headline>
|
</Headline>
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path={`${prop.match.path}/:id/reader`}>
|
<Route path={`:id/reader`}>
|
||||||
<Headline menu={menu_list(`${prop.match.path}/${id}`)} classes={{
|
<Headline menu={menu_list(location.pathname)}>
|
||||||
content:classes.noPaddingContent,
|
|
||||||
toolbar:classes.noPaddingToolbar
|
|
||||||
}}>
|
|
||||||
<ReaderPage doc={info.doc}></ReaderPage>
|
<ReaderPage doc={info.doc}></ReaderPage>
|
||||||
</Headline>
|
</Headline>
|
||||||
</Route>
|
</Route>
|
||||||
<Route>
|
<Route>
|
||||||
<NotFoundPage></NotFoundPage>
|
<NotFoundPage></NotFoundPage>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>);
|
</Routes>);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { CommonMenuList, Headline } from "../component/mod";
|
import { CommonMenuList, Headline } from "../component/mod";
|
||||||
import { UserContext } from "../state";
|
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';
|
import {Stack} from '@mui/material';
|
||||||
|
|
||||||
const useStyles = makeStyles((theme:Theme)=>({
|
const useStyles = ((theme:Theme)=>({
|
||||||
paper:{
|
paper:{
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
},
|
},
|
||||||
@ -30,12 +30,12 @@ function TypeDifference(prop:{
|
|||||||
onCommit:(v:{type:string,path:string})=>void,
|
onCommit:(v:{type:string,path:string})=>void,
|
||||||
onCommitAll:(type:string) => void
|
onCommitAll:(type:string) => void
|
||||||
}){
|
}){
|
||||||
const classes = useStyles();
|
//const classes = useStyles();
|
||||||
const x = prop.content;
|
const x = prop.content;
|
||||||
const [button_disable,set_disable] = useState(false);
|
const [button_disable,set_disable] = useState(false);
|
||||||
|
|
||||||
return (<Paper className={classes.paper}>
|
return (<Paper /*className={classes.paper}*/>
|
||||||
<Box className={classes.contentTitle}>
|
<Box /*className={classes.contentTitle}*/>
|
||||||
<Typography variant='h3' >{x.type}</Typography>
|
<Typography variant='h3' >{x.type}</Typography>
|
||||||
<Button variant="contained" key={x.type} onClick={()=>{
|
<Button variant="contained" key={x.type} onClick={()=>{
|
||||||
set_disable(true);
|
set_disable(true);
|
||||||
@ -44,7 +44,7 @@ function TypeDifference(prop:{
|
|||||||
}}>Commit all</Button>
|
}}>Commit all</Button>
|
||||||
</Box>
|
</Box>
|
||||||
{x.value.map(y=>(
|
{x.value.map(y=>(
|
||||||
<Box className={classes.commitable} key={y.path}>
|
<Box /*className={classes.commitable}*/ key={y.path}>
|
||||||
<Button variant="contained" onClick={()=>{
|
<Button variant="contained" onClick={()=>{
|
||||||
set_disable(true);
|
set_disable(true);
|
||||||
prop.onCommit(y);
|
prop.onCommit(y);
|
||||||
@ -59,7 +59,7 @@ function TypeDifference(prop:{
|
|||||||
|
|
||||||
export function DifferencePage(){
|
export function DifferencePage(){
|
||||||
const ctx = useContext(UserContext);
|
const ctx = useContext(UserContext);
|
||||||
const classes = useStyles();
|
//const classes = useStyles();
|
||||||
const [diffList,setDiffList] = useState<
|
const [diffList,setDiffList] = useState<
|
||||||
FileDifference[]
|
FileDifference[]
|
||||||
>([]);
|
>([]);
|
||||||
|
@ -1,22 +1,13 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { Headline, CommonMenuList,LoadingCircle, ContentInfo, NavList, NavItem, TagChip } from '../component/mod';
|
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 { Box, Typography, Chip } from '@mui/material';
|
||||||
import {useTheme, makeStyles, Theme} from '@material-ui/core/styles';
|
|
||||||
import ContentAccessor,{QueryListOption, Document} from '../accessor/document';
|
import ContentAccessor,{QueryListOption, Document} from '../accessor/document';
|
||||||
import {Link as RouterLink} from 'react-router-dom';
|
|
||||||
import {toQueryString} from '../accessor/util';
|
import {toQueryString} from '../accessor/util';
|
||||||
|
|
||||||
import {useLocation} from 'react-router-dom';
|
import {useLocation} from 'react-router-dom';
|
||||||
import { QueryStringToMap } from '../accessor/util';
|
import { QueryStringToMap } from '../accessor/util';
|
||||||
|
|
||||||
const useStyles = makeStyles((theme:Theme)=>({
|
|
||||||
root:{
|
|
||||||
display:"grid",
|
|
||||||
gridGap: theme.spacing(4),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export type GalleryProp = {
|
export type GalleryProp = {
|
||||||
option?:QueryListOption;
|
option?:QueryListOption;
|
||||||
diff:string;
|
diff:string;
|
||||||
@ -28,6 +19,7 @@ type GalleryState = {
|
|||||||
export const GalleryInfo = (props: GalleryProp)=>{
|
export const GalleryInfo = (props: GalleryProp)=>{
|
||||||
const [state,setState]= useState<GalleryState>({documents:undefined});
|
const [state,setState]= useState<GalleryState>({documents:undefined});
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
const abortController = new AbortController();
|
||||||
const load = (async ()=>{
|
const load = (async ()=>{
|
||||||
const c = await ContentAccessor.findList(props.option);
|
const c = await ContentAccessor.findList(props.option);
|
||||||
//todo : if c is undefined, retry to fetch 3 times. and show error message.
|
//todo : if c is undefined, retry to fetch 3 times. and show error message.
|
||||||
@ -35,14 +27,15 @@ export const GalleryInfo = (props: GalleryProp)=>{
|
|||||||
})
|
})
|
||||||
load();
|
load();
|
||||||
},[props.diff]);
|
},[props.diff]);
|
||||||
const classes = useStyles();
|
|
||||||
const queryString = toQueryString(props.option??{});
|
const queryString = toQueryString(props.option??{});
|
||||||
|
|
||||||
if(state.documents === undefined){
|
if(state.documents === undefined){
|
||||||
return (<LoadingCircle/>);
|
return (<LoadingCircle/>);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return (<Box className={classes.root}>
|
return (<Box sx={{
|
||||||
|
display:'grid'
|
||||||
|
}}>
|
||||||
{props.option !== undefined && props.diff !== "" && <Box>
|
{props.option !== undefined && props.diff !== "" && <Box>
|
||||||
<Typography variant="h6">search for</Typography>
|
<Typography variant="h6">search for</Typography>
|
||||||
{props.option.word !== undefined && <Chip label={"search : "+props.option.word}></Chip>}
|
{props.option.word !== undefined && <Chip label={"search : "+props.option.word}></Chip>}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import {CommonMenuList, Headline} from '../component/mod';
|
import {CommonMenuList, Headline} from '../component/mod';
|
||||||
import { Button, Dialog, DialogActions, DialogContent, DialogContentText,
|
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 { UserContext } from '../state';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {doLogin as doSessionLogin} from '../state';
|
import {doLogin as doSessionLogin} from '../state';
|
||||||
|
|
||||||
export const LoginPage = ()=>{
|
export const LoginPage = ()=>{
|
||||||
@ -11,7 +11,7 @@ export const LoginPage = ()=>{
|
|||||||
const [userLoginInfo,setUserLoginInfo]= useState({username:"",password:""});
|
const [userLoginInfo,setUserLoginInfo]= useState({username:"",password:""});
|
||||||
const [openDialog,setOpenDialog] = useState({open:false,message:""});
|
const [openDialog,setOpenDialog] = useState({open:false,message:""});
|
||||||
const {setUsername,setPermission} = useContext(UserContext);
|
const {setUsername,setPermission} = useContext(UserContext);
|
||||||
const history = useHistory();
|
const navigate = useNavigate();
|
||||||
const handleDialogClose = ()=>{
|
const handleDialogClose = ()=>{
|
||||||
setOpenDialog({...openDialog,open:false});
|
setOpenDialog({...openDialog,open:false});
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ export const LoginPage = ()=>{
|
|||||||
else console.error(e);
|
else console.error(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
history.push("/");
|
navigate("/");
|
||||||
}
|
}
|
||||||
const menu = CommonMenuList();
|
const menu = CommonMenuList();
|
||||||
return <Headline menu={menu}>
|
return <Headline menu={menu}>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { CommonMenuList, Headline } from "../component/mod";
|
import { CommonMenuList, Headline } from "../component/mod";
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState } from 'react';
|
||||||
import { UserContext } from "../state";
|
import { UserContext } from "../state";
|
||||||
import { Chip, Grid, makeStyles, Paper, Theme, Typography, Divider, Button,
|
import { Chip, Grid, Paper, Theme, Typography, Divider, Button,
|
||||||
Dialog, DialogTitle, DialogContentText, DialogContent, TextField, DialogActions } from "@material-ui/core";
|
Dialog, DialogTitle, DialogContentText, DialogContent, TextField, DialogActions } from "@mui/material";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme:Theme)=>({
|
const useStyles = ((theme:Theme)=>({
|
||||||
paper:{
|
paper:{
|
||||||
alignSelf:"center",
|
alignSelf:"center",
|
||||||
padding:theme.spacing(2),
|
padding:theme.spacing(2),
|
||||||
@ -17,7 +17,7 @@ const useStyles = makeStyles((theme:Theme)=>({
|
|||||||
|
|
||||||
export function ProfilePage(){
|
export function ProfilePage(){
|
||||||
const userctx = useContext(UserContext);
|
const userctx = useContext(UserContext);
|
||||||
const classes = useStyles();
|
//const classes = useStyles();
|
||||||
const menu = CommonMenuList();
|
const menu = CommonMenuList();
|
||||||
const [pw_open,set_pw_open] = useState(false);
|
const [pw_open,set_pw_open] = useState(false);
|
||||||
const [oldpw,setOldpw] = useState("");
|
const [oldpw,setOldpw] = useState("");
|
||||||
@ -66,7 +66,7 @@ export function ProfilePage(){
|
|||||||
handle_close();
|
handle_close();
|
||||||
}
|
}
|
||||||
return (<Headline menu={menu}>
|
return (<Headline menu={menu}>
|
||||||
<Paper className={classes.paper}>
|
<Paper /*className={classes.paper}*/>
|
||||||
<Grid container direction="column" alignItems="center">
|
<Grid container direction="column" alignItems="center">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Typography variant='h4'>{userctx.username}</Typography>
|
<Typography variant='h4'>{userctx.username}</Typography>
|
||||||
@ -87,7 +87,7 @@ export function ProfilePage(){
|
|||||||
<DialogTitle>Password Reset</DialogTitle>
|
<DialogTitle>Password Reset</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Typography>type the old and new password</Typography>
|
<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"
|
{(!isElectronContent) && (<TextField autoFocus margin='dense' type="password" label="old password"
|
||||||
value={oldpw} onChange={(e)=>setOldpw(e.target.value)}></TextField>)}
|
value={oldpw} onChange={(e)=>setOldpw(e.target.value)}></TextField>)}
|
||||||
<TextField margin='dense' type="password" label="new password"
|
<TextField margin='dense' type="password" label="new password"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect} from 'react';
|
||||||
import { Typography, useTheme } from '@material-ui/core';
|
import { Typography, useTheme } from '@mui/material';
|
||||||
import { Document } from '../../accessor/document';
|
import { Document } from '../../accessor/document';
|
||||||
|
|
||||||
type ComicType = "comic"|"artist cg"|"donjinshi"|"western"
|
type ComicType = "comic"|"artist cg"|"donjinshi"|"western"
|
||||||
@ -14,7 +14,6 @@ export type PresentableTag = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ComicReader = (props:{doc:Document})=>{
|
export const ComicReader = (props:{doc:Document})=>{
|
||||||
const theme = useTheme();
|
|
||||||
const additional = props.doc.additional;
|
const additional = props.doc.additional;
|
||||||
const [curPage,setCurPage] = useState(0);
|
const [curPage,setCurPage] = useState(0);
|
||||||
if(!('page' in additional)){
|
if(!('page' in additional)){
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from '@mui/material';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Document, makeThumbnailUrl } from '../../accessor/document';
|
import { Document, makeThumbnailUrl } from '../../accessor/document';
|
||||||
import {ComicReader} from './comic';
|
import {ComicReader} from './comic';
|
||||||
@ -22,10 +22,10 @@ export const getPresenter = (content:Document):PagePresenter => {
|
|||||||
return ()=><Typography variant='h2'>Not implemented reader</Typography>;
|
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);
|
const thumbnailurl = makeThumbnailUrl(props.content);
|
||||||
if(props.content.content_type === "video"){
|
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 React from 'react';
|
||||||
import {Typography, Paper} from '@material-ui/core';
|
import {Typography, Paper} from '@mui/material';
|
||||||
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
import {ArrowBack as ArrowBackIcon} from '@mui/icons-material';
|
||||||
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
import { Headline, BackItem, NavList, CommonMenuList } from '../component/mod';
|
||||||
|
|
||||||
export const SettingPage = ()=>{
|
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();
|
const setting = get_setting();
|
||||||
static_file_server('dist/css/style.css','css');
|
static_file_server('dist/bundle.css','css');
|
||||||
static_file_server('dist/js/bundle.js','js');
|
static_file_server('dist/bundle.js','js');
|
||||||
if(setting.mode === "development")
|
if(setting.mode === "development"){
|
||||||
static_file_server('dist/js/bundle.js.map','text');
|
static_file_server('dist/bundle.js.map','text');
|
||||||
|
static_file_server('dist/bundle.css.map','text');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start_server(){
|
start_server(){
|
||||||
let setting = get_setting();
|
let setting = get_setting();
|
||||||
|
Loading…
Reference in New Issue
Block a user