back link feature
This commit is contained in:
parent
5002bc22f9
commit
714ba9aae7
@ -15,3 +15,21 @@ export const toQueryString = (obj:ToQueryStringA)=> {
|
|||||||
: `${e[0]}=${encodeURIComponent(e[1])}`)
|
: `${e[0]}=${encodeURIComponent(e[1])}`)
|
||||||
.join('&');
|
.join('&');
|
||||||
}
|
}
|
||||||
|
export const QueryStringToMap = (query:string) =>{
|
||||||
|
const keyValue = query.slice(query.indexOf("?")+1).split("&");
|
||||||
|
const param:{[k:string]:string|string[]} = {};
|
||||||
|
keyValue.forEach((p)=>{
|
||||||
|
const [k,v] = p.split("=");
|
||||||
|
if(k.endsWith("[]")){
|
||||||
|
let arr = param[k];
|
||||||
|
if(arr instanceof Array){
|
||||||
|
arr.push(v);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param[k] = [v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else param[k] = v;
|
||||||
|
});
|
||||||
|
return param;
|
||||||
|
}
|
@ -1,13 +1,17 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { createContext, useRef, useState } from 'react';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import {BrowserRouter, Route, Switch as RouterSwitch} from 'react-router-dom';
|
import {BrowserRouter, Route, Switch as RouterSwitch} from 'react-router-dom';
|
||||||
import { Gallery, ContentAbout} from './page/mod';
|
import { Gallery, ContentAbout} from './page/mod';
|
||||||
|
import {BackLinkContext} from './state';
|
||||||
|
|
||||||
import './css/style.css';
|
import './css/style.css';
|
||||||
|
|
||||||
const FooProfile = ()=><div>test profile</div>;
|
const FooProfile = ()=><div>test profile</div>;
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (<BrowserRouter>
|
const [path,setPath] = useState("/");
|
||||||
|
return (
|
||||||
|
<BackLinkContext.Provider value={{path:path,setPath:setPath}}>
|
||||||
|
<BrowserRouter>
|
||||||
<RouterSwitch>
|
<RouterSwitch>
|
||||||
<Route path="/" exact render={()=><Gallery />}></Route>
|
<Route path="/" exact render={()=><Gallery />}></Route>
|
||||||
<Route path="/search" render={()=><Gallery />}></Route>
|
<Route path="/search" render={()=><Gallery />}></Route>
|
||||||
@ -17,7 +21,8 @@ const App = () => {
|
|||||||
<div>404 Not Found</div>
|
<div>404 Not Found</div>
|
||||||
</Route>
|
</Route>
|
||||||
</RouterSwitch>
|
</RouterSwitch>
|
||||||
</BrowserRouter>);
|
</BrowserRouter>
|
||||||
|
</BackLinkContext.Provider>);
|
||||||
};
|
};
|
||||||
|
|
||||||
ReactDom.render(
|
ReactDom.render(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
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 { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink, useParams, useLocation } from 'react-router-dom';
|
||||||
import ContentAccessor, { Content } from '../accessor/contents';
|
import ContentAccessor, { Content } from '../accessor/contents';
|
||||||
import { LoadingCircle } from '../component/loading';
|
import { LoadingCircle } from '../component/loading';
|
||||||
@ -6,6 +6,7 @@ import { Link, Paper, makeStyles, Theme, Box, useTheme, Typography } from '@mate
|
|||||||
import {ArrowBack as ArrowBackIcon } from '@material-ui/icons';
|
import {ArrowBack as ArrowBackIcon } from '@material-ui/icons';
|
||||||
import { MangaReader } from './reader/manga';
|
import { MangaReader } from './reader/manga';
|
||||||
import { ContentInfo, Headline, NavItem, NavList } from '../component/mod';
|
import { ContentInfo, Headline, NavItem, NavList } from '../component/mod';
|
||||||
|
import {BackLinkContext} from '../state';
|
||||||
|
|
||||||
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
|
||||||
export const makeMangaReaderUrl = (id: number) => `/doc/${id}/reader`;
|
export const makeMangaReaderUrl = (id: number) => `/doc/${id}/reader`;
|
||||||
@ -24,9 +25,15 @@ export const ContentAbout = (prop: { match: MatchType }) => {
|
|||||||
const [info, setInfo] = useState<ContentState>({ content: undefined, notfound:false });
|
const [info, setInfo] = useState<ContentState>({ content: undefined, notfound:false });
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
console.log("state : "+location.state);
|
console.log("state : "+location.state);
|
||||||
const menu_list = (
|
const menu_list = (link?:string)=>(
|
||||||
<NavList>
|
<NavList>
|
||||||
<NavItem name="Back" to="/" icon={<ArrowBackIcon/>}></NavItem>
|
<BackLinkContext.Consumer>
|
||||||
|
{
|
||||||
|
(ctx) => link === undefined ?
|
||||||
|
<NavItem name="Back" to={ctx.path} icon={<ArrowBackIcon/>}/>
|
||||||
|
: <NavItem name="Back" to={link} icon={<ArrowBackIcon/>}/>
|
||||||
|
}
|
||||||
|
</BackLinkContext.Consumer>
|
||||||
</NavList>
|
</NavList>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -42,39 +49,43 @@ export const ContentAbout = (prop: { match: MatchType }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
return (
|
return (
|
||||||
<Headline menu={menu_list}>
|
<Headline menu={menu_list()}>
|
||||||
<Typography variant='h2'>Oops. Invalid ID</Typography>
|
<Typography variant='h2'>Oops. Invalid ID</Typography>
|
||||||
</Headline>
|
</Headline>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if(info.notfound){
|
else if(info.notfound){
|
||||||
return (
|
return (
|
||||||
<Headline menu={menu_list}>
|
<Headline menu={menu_list()}>
|
||||||
<Typography variant='h2'>Content has been removed.</Typography>
|
<Typography variant='h2'>Content has been removed.</Typography>
|
||||||
</Headline>
|
</Headline>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else if (info.content === undefined) {
|
else if (info.content === undefined) {
|
||||||
return (<Headline menu={menu_list}>
|
return (<Headline menu={menu_list()}>
|
||||||
<LoadingCircle />
|
<LoadingCircle />
|
||||||
</Headline>
|
</Headline>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else return (<Switch>
|
else{
|
||||||
|
|
||||||
|
return (<Switch>
|
||||||
<Route exact path={`${prop.match.path}/:id`}>
|
<Route exact path={`${prop.match.path}/:id`}>
|
||||||
<Headline menu={menu_list}>
|
|
||||||
|
<Headline menu={menu_list()}>
|
||||||
<ContentInfo content={info.content}></ContentInfo>
|
<ContentInfo content={info.content}></ContentInfo>
|
||||||
</Headline>
|
</Headline>
|
||||||
</Route>
|
</Route>
|
||||||
<Route exact path={`${prop.match.path}/:id/reader`}>
|
<Route exact path={`${prop.match.path}/:id/reader`}>
|
||||||
<Headline menu={menu_list}>
|
<Headline menu={menu_list(`${prop.match.path}/${id}`)}>
|
||||||
<MangaReader content={info.content}></MangaReader>
|
<MangaReader content={info.content}></MangaReader>
|
||||||
</Headline>
|
</Headline>
|
||||||
</Route>
|
</Route>
|
||||||
<Route>
|
<Route>
|
||||||
<Headline menu={menu_list}>
|
<Headline menu={menu_list()}>
|
||||||
<div>404 Not Found invalid url : {prop.match.path}</div>
|
<div>404 Not Found invalid url : {prop.match.path}</div>
|
||||||
</Headline>
|
</Headline>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>);
|
</Switch>);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,14 +1,22 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { NavList, NavItem, Headline } from '../component/mod';
|
import { NavList, NavItem, Headline } from '../component/mod';
|
||||||
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
import {ArrowBack as ArrowBackIcon} from '@material-ui/icons';
|
||||||
import {GalleryInfo} from '../component/mod';
|
import {GalleryInfo} from '../component/mod';
|
||||||
|
import {BackLinkContext} from '../state';
|
||||||
|
import {useLocation} from 'react-router-dom';
|
||||||
|
import { QueryStringToMap } from '../accessor/util';
|
||||||
|
|
||||||
export const Gallery = ()=>{
|
export const Gallery = ()=>{
|
||||||
|
const location = useLocation();
|
||||||
|
const backctx = useContext(BackLinkContext);
|
||||||
|
backctx.setPath("/");
|
||||||
|
|
||||||
|
const query = QueryStringToMap(location.search);
|
||||||
const menu_list = (<NavList>
|
const menu_list = (<NavList>
|
||||||
<NavItem name="Back" to="" icon={<ArrowBackIcon></ArrowBackIcon>}></NavItem>
|
{Object.keys(query).length !== 0 && <NavItem name="Back" to="/" icon={<ArrowBackIcon></ArrowBackIcon>}></NavItem>}
|
||||||
</NavList>);
|
</NavList>);
|
||||||
|
|
||||||
return (<Headline menu={menu_list}>
|
return (<Headline menu={menu_list}>
|
||||||
<GalleryInfo></GalleryInfo>
|
<GalleryInfo option={query}></GalleryInfo>
|
||||||
</Headline>)
|
</Headline>)
|
||||||
}
|
}
|
@ -22,7 +22,7 @@ export const MangaReader = (props:{content:Content})=>{
|
|||||||
return <Typography>Error. DB error. page restriction</Typography>
|
return <Typography>Error. DB error. page restriction</Typography>
|
||||||
}
|
}
|
||||||
const page:number = additional['page'] as number;
|
const page:number = additional['page'] as number;
|
||||||
return (<div>{[...Array(page).keys()].map(x=>(<img src={`/content/${props.content.id}/manga/${x}`} style={{maxHeight:'100%',maxWidth:'100%'}}></img>))}</div>);
|
return (<div>{[...Array(page).keys()].map(x=>(<img src={`/content/${props.content.id}/manga/${x}`} key={x} style={{maxHeight:'100%',maxWidth:'100%'}}></img>))}</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MangaReader;
|
export default MangaReader;
|
3
src/client/state.tsx
Normal file
3
src/client/state.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import React, { createContext, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export const BackLinkContext = createContext({path:"",setPath:(s:string)=>{}});
|
@ -47,6 +47,12 @@ async function main(){
|
|||||||
ctx.body = index_html;
|
ctx.body = index_html;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
router.get('/search'
|
||||||
|
,async (ctx,next)=>{
|
||||||
|
ctx.type = "html";
|
||||||
|
ctx.body = index_html;
|
||||||
|
}
|
||||||
|
);
|
||||||
let content_router = getContentRouter(createKnexContentsAccessor(db));
|
let content_router = getContentRouter(createKnexContentsAccessor(db));
|
||||||
router.use('/content',content_router.routes());
|
router.use('/content',content_router.routes());
|
||||||
router.use('/content',content_router.allowedMethods());
|
router.use('/content',content_router.allowedMethods());
|
||||||
|
Loading…
Reference in New Issue
Block a user