simple search
This commit is contained in:
parent
7a3fdce4dc
commit
1eba3e43e7
@ -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>
|
||||
|
@ -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 :
|
||||
|
@ -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={{
|
||||
|
@ -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>);
|
||||
);
|
||||
}
|
||||
}
|
@ -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>)
|
||||
}
|
@ -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[],
|
||||
|
@ -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)=>{
|
||||
|
Loading…
Reference in New Issue
Block a user