back link feature
This commit is contained in:
		
							parent
							
								
									5002bc22f9
								
							
						
					
					
						commit
						714ba9aae7
					
				
					 7 changed files with 77 additions and 26 deletions
				
			
		| 
						 | 
					@ -14,4 +14,22 @@ export const toQueryString = (obj:ToQueryStringA)=> {
 | 
				
			||||||
            ? e[1].map(f=>`${e[0]}[]=${encodeURIComponent(f)}`).join('&') 
 | 
					            ? e[1].map(f=>`${e[0]}[]=${encodeURIComponent(f)}`).join('&') 
 | 
				
			||||||
            : `${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,23 +1,28 @@
 | 
				
			||||||
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("/");
 | 
				
			||||||
            <RouterSwitch>
 | 
					    return (
 | 
				
			||||||
                <Route path="/" exact render={()=><Gallery />}></Route>
 | 
					    <BackLinkContext.Provider value={{path:path,setPath:setPath}}>
 | 
				
			||||||
                <Route path="/search" render={()=><Gallery />}></Route>
 | 
					        <BrowserRouter>
 | 
				
			||||||
                <Route path="/doc" render={(prop)=><ContentAbout {...prop}/>}></Route>
 | 
					                <RouterSwitch>
 | 
				
			||||||
                <Route path="/profile" component={FooProfile}></Route>
 | 
					                    <Route path="/" exact render={()=><Gallery />}></Route>
 | 
				
			||||||
                <Route>
 | 
					                    <Route path="/search" render={()=><Gallery />}></Route>
 | 
				
			||||||
                    <div>404 Not Found</div>
 | 
					                    <Route path="/doc" render={(prop)=><ContentAbout {...prop}/>}></Route>
 | 
				
			||||||
                </Route>
 | 
					                    <Route path="/profile" component={FooProfile}></Route>
 | 
				
			||||||
            </RouterSwitch>
 | 
					                    <Route>
 | 
				
			||||||
    </BrowserRouter>);
 | 
					                        <div>404 Not Found</div>
 | 
				
			||||||
 | 
					                    </Route>
 | 
				
			||||||
 | 
					                </RouterSwitch>
 | 
				
			||||||
 | 
					        </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…
	
	Add table
		
		Reference in a new issue