simple search

This commit is contained in:
monoid 2022-04-28 00:01:41 +09:00
parent 7a3fdce4dc
commit 1eba3e43e7
7 changed files with 89 additions and 35 deletions

View File

@ -1,7 +1,7 @@
import React, { createContext, useEffect, useRef, useState } from 'react';
import ReactDom from 'react-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, ReaderPage } from './page/mod';
import { getInitialValue, UserContext } from './state';
import { ThemeProvider, createTheme } from '@mui/material';
@ -32,7 +32,8 @@ const App = () => {
<Routes>
<Route path="/" element={<Navigate replace to='/search?' />} />
<Route path="/search" element={<Gallery />} />
<Route path="/doc" element={<DocumentAbout />}></Route>
<Route path="/doc/:id" element={<DocumentAbout />}></Route>
<Route path="/doc/:id/reader" element={<ReaderPage />}></Route>
<Route path="/login" element={<LoginPage></LoginPage>} />
<Route path="/profile" element={<ProfilePage />}></Route>
<Route path="/difference" element={<DifferencePage />}></Route>

View File

@ -83,7 +83,6 @@ export const ContentInfo = (props: {
//const classes = useStyles();
const theme = useTheme();
const document = props.document;
const propclasses = props.classes ?? {};
/*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 :

View File

@ -9,7 +9,7 @@ import {
ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle
} from '@mui/icons-material';
import { Link as RouterLink } from 'react-router-dom';
import { Link as RouterLink, useNavigate } from 'react-router-dom';
import { doLogout, UserContext } from '../state';
const drawerWidth = 270;
@ -80,6 +80,8 @@ export const Headline = (prop: {
const menuId = 'primary-search-account-menu';
const user_ctx = useContext(UserContext);
const isLogin = user_ctx.username !== "";
const navigate = useNavigate();
const [search, setSearch] = useState("");
const renderProfileMenu = (<Menu
anchorEl={anchorEl}
@ -139,9 +141,21 @@ export const Headline = (prop: {
alignItems: 'center',
justifyContent: 'center'
}}>
<SearchIcon />
<SearchIcon onClick={() => navigate(`/search?word=${encodeURIComponent(search)}`)} />
</div>
<StyledInputBase placeholder="search"></StyledInputBase>
<StyledInputBase placeholder="search"
onChange={(e) => setSearch(e.target.value)}
onKeyUp={(e) => {
if (e.key === "Enter") {
let words = search.includes("&") ? search.split("&") : [search];
words = words.map(w => w.trim())
.map(w => w.includes(":") ?
`allow_tag=${w}`
: `word=${encodeURIComponent(w)}`);
navigate(`/search?${words.join("&")}`);
}
}}
value={search}></StyledInputBase>
</StyledSearchBar>
{
isLogin ?
@ -159,7 +173,7 @@ export const Headline = (prop: {
</Toolbar>
</AppBar>
{renderProfileMenu}
<nav>
<nav style={{ width: theme.spacing(7) }}>
<Hidden smUp implementation="css">
<StyledDrawer variant="temporary" anchor='left' open={v} onClose={toggleV}
sx={{

View File

@ -1,11 +1,11 @@
import React, { useState, useEffect} from 'react';
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 { Theme, Typography } from '@mui/material';
import { getPresenter } from './reader/reader';
import { CommonMenuList, ContentInfo, Headline } from '../component/mod';
import {NotFoundPage} from './404';
import { NotFoundPage } from './404';
export const makeContentInfoUrl = (id: number) => `/doc/${id}`;
export const makeComicReaderUrl = (id: number) => `/doc/${id}/reader`;
@ -15,27 +15,27 @@ type DocumentState = {
notfound: boolean,
}
const styles = ((theme:Theme)=>({
noPaddingContent:{
display:'flex',
const styles = ((theme: Theme) => ({
noPaddingContent: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
noPaddingToolbar:{
noPaddingToolbar: {
flex: '0 1 auto',
...theme.mixins.toolbar,
}
}));
export const DocumentAbout = (prop?: {}) => {
export function ReaderPage(props?: {}) {
const location = useLocation();
const match = useParams<{id:string}>();
const match = useParams<{ id: string }>();
if (match == null) {
throw new Error("unreachable");
}
const id = Number.parseInt(match.id);
const [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound:false });
const menu_list = (link?:string) => <CommonMenuList url={link}></CommonMenuList>;
const [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound: false });
const menu_list = (link?: string) => <CommonMenuList url={link}></CommonMenuList>;
useEffect(() => {
(async () => {
@ -53,7 +53,7 @@ export const DocumentAbout = (prop?: {}) => {
</Headline>
);
}
else if(info.notfound){
else if (info.notfound) {
return (
<Headline menu={menu_list()}>
<Typography variant='h2'>Content has been removed.</Typography>
@ -66,22 +66,57 @@ export const DocumentAbout = (prop?: {}) => {
</Headline>
);
}
else{
else {
const ReaderPage = getPresenter(info.doc);
return (<Routes>
<Route path={`:id`}>
return <Headline menu={menu_list(location.pathname)}>
<ReaderPage doc={info.doc}></ReaderPage>
</Headline>
}
}
export const DocumentAbout = (prop?: {}) => {
const match = useParams<{ id: string }>();
if (match == null) {
throw new Error("unreachable");
}
const id = Number.parseInt(match.id);
const [info, setInfo] = useState<DocumentState>({ doc: undefined, notfound: false });
const menu_list = (link?: string) => <CommonMenuList url={link}></CommonMenuList>;
useEffect(() => {
(async () => {
if (!isNaN(id)) {
const c = await DocumentAccessor.findById(id);
setInfo({ doc: c, notfound: c === undefined });
}
})();
}, []);
if (isNaN(id)) {
return (
<Headline menu={menu_list()}>
<Typography variant='h2'>Oops. Invalid ID</Typography>
</Headline>
);
}
else if (info.notfound) {
return (
<Headline menu={menu_list()}>
<Typography variant='h2'>Content has been removed.</Typography>
</Headline>
)
}
else if (info.doc === undefined) {
return (<Headline menu={menu_list()}>
<LoadingCircle />
</Headline>
);
}
else {
return (
<Headline menu={menu_list()}>
<ContentInfo document={info.doc}></ContentInfo>
</Headline>
</Route>
<Route path={`:id/reader`}>
<Headline menu={menu_list(location.pathname)}>
<ReaderPage doc={info.doc}></ReaderPage>
</Headline>
</Route>
<Route>
<NotFoundPage></NotFoundPage>
</Route>
</Routes>);
);
}
}

View File

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useState } from 'react';
import { Headline, CommonMenuList,LoadingCircle, ContentInfo, NavList, NavItem, TagChip } from '../component/mod';
import { Box, Typography, Chip } from '@mui/material';
import { Box, Typography, Chip, Pagination } from '@mui/material';
import ContentAccessor,{QueryListOption, Document} from '../accessor/document';
import {toQueryString} from '../accessor/util';
@ -62,5 +62,6 @@ export const Gallery = ()=>{
option.limit = typeof query['limit'] === "string" ? parseInt(query['limit']) : undefined;
return (<Headline menu={menu_list}>
<GalleryInfo diff={location.search} option={query}></GalleryInfo>
</Headline>)
}

View File

@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react';
import { Typography, useTheme } from '@mui/material';
import { Document } from '../../accessor/document';
type ComicType = "comic"|"artist cg"|"donjinshi"|"western"
type ComicType = "comic"|"artist cg"|"donjinshi"|"western";
export type PresentableTag = {
artist:string[],

View File

@ -16,7 +16,11 @@ class KnexDocumentAccessor implements DocumentAccessor{
this.tagController = createKnexTagController(knex);
}
async search(search_word: string): Promise<Document[]>{
throw new Error("Not implemented");
throw new Error("Method not implemented.");
const sw = `%${search_word}%`;
const docs = await this.knex.select("*").from("document")
.where("title","like",sw);
return docs;
}
async addList(content_list: DocumentBody[]):Promise<number[]>{
return await this.knex.transaction(async (trx)=>{