headline
This commit is contained in:
		
							parent
							
								
									541de21e66
								
							
						
					
					
						commit
						5002bc22f9
					
				
					 9 changed files with 271 additions and 190 deletions
				
			
		|  | @ -1,27 +1,24 @@ | |||
| import React from 'react'; | ||||
| import React, { useRef, useState } from 'react'; | ||||
| import ReactDom from 'react-dom'; | ||||
| import {BrowserRouter, Route, Switch as RouterSwitch} from 'react-router-dom'; | ||||
| import {Headline} from './page/headline'; | ||||
| import {Gallery} from './page/gallery'; | ||||
| import {ContentAbout} from './page/contentinfo'; | ||||
| import { Gallery, ContentAbout} from './page/mod'; | ||||
| 
 | ||||
| import './css/style.css'; | ||||
| 
 | ||||
| const FooProfile = ()=><div>test profile</div>; | ||||
| const App = ()=> ( | ||||
|     <BrowserRouter> | ||||
|         <Headline> | ||||
| const App = () => { | ||||
|     return (<BrowserRouter> | ||||
|             <RouterSwitch> | ||||
|                 <Route path="/" exact component={Gallery}></Route> | ||||
|                 <Route path="/doc" component={ContentAbout}></Route> | ||||
|                 <Route path="/" exact render={()=><Gallery />}></Route> | ||||
|                 <Route path="/search" render={()=><Gallery />}></Route> | ||||
|                 <Route path="/doc" render={(prop)=><ContentAbout {...prop}/>}></Route> | ||||
|                 <Route path="/profile" component={FooProfile}></Route> | ||||
|                 <Route> | ||||
|                     <div>404 Not Found</div> | ||||
|                 </Route> | ||||
|             </RouterSwitch> | ||||
|         </Headline> | ||||
|     </BrowserRouter> | ||||
| ); | ||||
|     </BrowserRouter>); | ||||
| }; | ||||
| 
 | ||||
| ReactDom.render( | ||||
|     <App/>, | ||||
|  |  | |||
|  | @ -34,34 +34,93 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     title: { | ||||
|         marginLeft: theme.spacing(1), | ||||
|     }, | ||||
|     InfoContainer: { | ||||
|     infoContainer: { | ||||
|         padding: theme.spacing(2), | ||||
|     }, | ||||
|     subinfoContainer: { | ||||
|         display: 'grid', | ||||
|         gridTemplateColumns: '100px auto', | ||||
|         overflowY: 'hidden', | ||||
|     }, | ||||
|     short_subinfoContainer:{ | ||||
|         [theme.breakpoints.up("xs")]:{ | ||||
|             display:'none', | ||||
|         } | ||||
|     }, | ||||
|     short_root:{ | ||||
|         overflowY:'hidden', | ||||
|         display:'flex', | ||||
|         flexDirection: 'column', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             height:200, | ||||
|             flexDirection: 'row', | ||||
|         }, | ||||
|     }, | ||||
|     short_thumbnail_anchor:{ | ||||
|         background: '#272733', | ||||
|         display: 'flex', | ||||
|         alignItems: 'center', | ||||
|         justifyContent: 'center', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             width: theme.spacing(25), | ||||
|             height: theme.spacing(25), | ||||
|             flexShrink: 0, | ||||
|         } | ||||
|     }, | ||||
|     short_thumbnail_content: { | ||||
|         maxWidth: '100%', | ||||
|         maxHeight: '100%', | ||||
|     }, | ||||
| })) | ||||
| 
 | ||||
| export const ContentInfo = (props: { content: Content, children?: React.ReactNode }) => { | ||||
| export const ContentInfo = (props: { | ||||
|     content: Content, children?: React.ReactNode, classes?: { | ||||
|         root?: string, | ||||
|         thumbnail_anchor?: string, | ||||
|         thumbnail_content?: string, | ||||
|         tag_list?: string, | ||||
|         title?: string, | ||||
|         infoContainer?: string, | ||||
|         subinfoContainer?: string | ||||
|     }, | ||||
|     gallery?:string, | ||||
|     short?:boolean | ||||
| }) => { | ||||
|     const classes = useStyles(); | ||||
|     const theme = useTheme(); | ||||
|     const content = props?.content; | ||||
|     const content = props.content; | ||||
|     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 : | ||||
|         classes.thumbnail_content; | ||||
|     const subinfoContainer = props.short ? classes.short_subinfoContainer : | ||||
|         classes.subinfoContainer; | ||||
|     let allTag = content.tags; | ||||
|     const artists = allTag.filter(x => x.startsWith("artist:")).map(x => x.substr(7)); | ||||
|     allTag = allTag.filter(x => !x.startsWith("artist:")); | ||||
|     return (<Paper className={classes.root}> | ||||
|         <Link component={RouterLink} to={makeContentReaderUrl(content.id)}> | ||||
|             <ThumbnailContainer content={content} className={classes.thumbnail_content}></ThumbnailContainer> | ||||
|     return (<Paper className={propclasses.root || rootName} elevation={4}> | ||||
|         <Link className={propclasses.thumbnail_anchor || thumbnail_anchor} component={RouterLink} to={{ | ||||
|             pathname:makeContentReaderUrl(content.id), | ||||
|             state:props.gallery | ||||
|         }}> | ||||
|             <ThumbnailContainer content={content}  | ||||
|                 className={propclasses.thumbnail_content || thumbnail_content}/> | ||||
|         </Link> | ||||
|         <Box style={{ padding: theme.spacing(1) }}> | ||||
|             <Link variant='h5' color='inherit' component={RouterLink} to={makeContentReaderUrl(content.id)} | ||||
|                 className={classes.title}> | ||||
|         <Box className={propclasses.infoContainer || classes.infoContainer}> | ||||
|             <Link variant='h5' color='inherit' component={RouterLink} to={{ | ||||
|                 pathname: props.gallery === undefined ? makeContentReaderUrl(content.id) : makeContentInfoUrl(content.id), | ||||
|                 state:props.gallery | ||||
|             }} | ||||
|                 className={propclasses.title || classes.title}> | ||||
|                 {content.title} | ||||
|             </Link> | ||||
|             <Box className={classes.InfoContainer}> | ||||
|             <Box className={propclasses.subinfoContainer || subinfoContainer}> | ||||
|                 <Typography variant='subtitle1'>Artist</Typography> | ||||
|                 <Box style={{alignSelf:"center"}}>{artists.join(", ")}</Box> | ||||
|                 <Box style={{ alignSelf: "center" }}>{artists.join(", ")}</Box> | ||||
|                 <Typography variant='subtitle1'>Tags</Typography> | ||||
|                 <Box className={classes.tag_list}> | ||||
|                 <Box className={propclasses.tag_list || classes.tag_list}> | ||||
|                     {allTag.map(x => { | ||||
|                         return (<TagChip key={x} label={x} clickable={true} tagname={x} size="small"></TagChip>); | ||||
|                     })} | ||||
|  |  | |||
							
								
								
									
										71
									
								
								src/client/component/galleryinfo.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/client/component/galleryinfo.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| import { Box, Paper, Link, useMediaQuery, Portal, List, ListItem, ListItemIcon, Tooltip, ListItemText } from '@material-ui/core'; | ||||
| import {useTheme, makeStyles, Theme} from '@material-ui/core/styles'; | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import ContentAccessor,{QueryListOption, Content} from '../accessor/contents'; | ||||
| import {Link as RouterLink} from 'react-router-dom'; | ||||
| import { LoadingCircle, ContentInfo, NavList, NavItem } from './mod'; | ||||
| import {toQueryString} from '../accessor/util'; | ||||
| 
 | ||||
| 
 | ||||
| const useStyles = makeStyles((theme:Theme)=>({ | ||||
|     root:{ | ||||
|         display:"grid", | ||||
|         gridGap: theme.spacing(4), | ||||
|     }, | ||||
|     anchor_thumbnail:{ | ||||
|         background: '#272733', | ||||
|         display: 'flex', | ||||
|         alignItems: 'center', | ||||
|         justifyContent: 'center', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             width: theme.spacing(25), | ||||
|             height: theme.spacing(25), | ||||
|             flexShrink: 0, | ||||
|         } | ||||
|     }, | ||||
|     contentPaper:{ | ||||
|         overflowY:'hidden', | ||||
|         display:'flex', | ||||
|         flexDirection: 'column', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             height:200, | ||||
|             flexDirection: 'row', | ||||
|         }, | ||||
|     }, | ||||
|     content_thumnail: { | ||||
|         maxWidth: '100%', | ||||
|         maxHeight: '100%', | ||||
|     }, | ||||
| })); | ||||
| 
 | ||||
| export type GalleryProp = { | ||||
|     option?:QueryListOption; | ||||
| }; | ||||
| type GalleryState = { | ||||
|     content:Content[]|undefined; | ||||
| } | ||||
| 
 | ||||
| export const GalleryInfo = (props: GalleryProp)=>{ | ||||
|     const [state,setState]= useState<GalleryState>({content:undefined}); | ||||
|     useEffect(()=>{ | ||||
|         (async ()=>{ | ||||
|             const c = await ContentAccessor.findList(props.option); | ||||
|             setState({content:c}); | ||||
|         })() | ||||
|     },[props.option]); | ||||
|     const classes = useStyles(); | ||||
|     const queryString = toQueryString(props.option||{}); | ||||
| 
 | ||||
|     if(state.content === undefined){ | ||||
|         return (<LoadingCircle/>); | ||||
|     } | ||||
|     else{ | ||||
|         return (<Box className={classes.root}>{ | ||||
|             state.content.map(x=>{ | ||||
|                 return (<ContentInfo content={x} key={x.id}  | ||||
|                     gallery={`/search?${queryString}`} short/>); | ||||
|             }) | ||||
|             } | ||||
|             </Box>); | ||||
|     } | ||||
| } | ||||
|  | @ -1,13 +1,13 @@ | |||
| import ReactDom from 'react-dom'; | ||||
| import React, { useState } from 'react'; | ||||
| import React, { ReactNode, useState } from 'react'; | ||||
| import { | ||||
|     Button, CssBaseline, Divider, IconButton, List, ListItem, Drawer, | ||||
|     AppBar, Toolbar, Typography, InputBase, ListItemIcon, ListItemText, Menu, MenuItem, | ||||
|     Hidden, Tooltip | ||||
|     Hidden, Tooltip, Link | ||||
| } from '@material-ui/core'; | ||||
| import { makeStyles, Theme, useTheme, fade } from '@material-ui/core/styles'; | ||||
| import { ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, ArrowBack as ArrowBackIcon, AccountCircle } from '@material-ui/icons'; | ||||
| import {Link} from 'react-router-dom'; | ||||
| import { ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle } from '@material-ui/icons'; | ||||
| import { Link as RouterLink, useRouteMatch } from 'react-router-dom'; | ||||
| 
 | ||||
| const drawerWidth = 240; | ||||
| 
 | ||||
|  | @ -31,7 +31,7 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     drawer: { | ||||
|         flexShrink: 0, | ||||
|         whiteSpace: "nowrap", | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|         [theme.breakpoints.up("sm")]: { | ||||
|             width: drawerWidth, | ||||
|         }, | ||||
|     }, | ||||
|  | @ -40,7 +40,7 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     }, | ||||
|     drawerClose: { | ||||
|         overflowX: 'hidden', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|         [theme.breakpoints.up("sm")]: { | ||||
|             width: theme.spacing(7) + 1, | ||||
|         }, | ||||
|     }, | ||||
|  | @ -48,7 +48,7 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|         ...theme.mixins.toolbar, | ||||
|     }, | ||||
|     content: { | ||||
|         display:'flex', | ||||
|         display: 'flex', | ||||
|         flexFlow: 'column', | ||||
|         flexGrow: 1, | ||||
|         padding: theme.spacing(3), | ||||
|  | @ -104,27 +104,32 @@ const useStyles = makeStyles((theme: Theme) => ({ | |||
|     }, | ||||
| })); | ||||
| 
 | ||||
| export const Headline = (prop: { children?: React.ReactNode, navListItem?: React.ReactNode, isLogin?:boolean}) => { | ||||
| export const Headline = (prop: { | ||||
|     children?: React.ReactNode, | ||||
|     navListItem?: React.ReactNode, | ||||
|     isLogin?: boolean, | ||||
|     menu: React.ReactNode | ||||
| }) => { | ||||
|     const [v, setv] = useState(false); | ||||
|     const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); | ||||
|     const classes = useStyles(); | ||||
|     const theme = useTheme(); | ||||
|     const toggleV = () => setv(!v); | ||||
|     const handleProfileMenuOpen = (e:React.MouseEvent<HTMLElement>)=>setAnchorEl(e.currentTarget); | ||||
|     const handleProfileMenuClose = ()=>setAnchorEl(null); | ||||
|     const handleProfileMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget); | ||||
|     const handleProfileMenuClose = () => setAnchorEl(null); | ||||
|     const isProfileMenuOpened = Boolean(anchorEl); | ||||
|     const menuId = 'primary-search-account-menu'; | ||||
|     const isLogin = prop.isLogin || false; | ||||
|     const renderProfileMenu = (<Menu | ||||
|         anchorEl={anchorEl} | ||||
|         anchorOrigin={{horizontal:'right',vertical:"top"}} | ||||
|         anchorOrigin={{ horizontal: 'right', vertical: "top" }} | ||||
|         id={menuId} | ||||
|         open={isProfileMenuOpened} | ||||
|         keepMounted | ||||
|         transformOrigin={{horizontal:'right',vertical:"top"}} | ||||
|         transformOrigin={{ horizontal: 'right', vertical: "top" }} | ||||
|         onClose={handleProfileMenuClose} | ||||
|     > | ||||
|         <MenuItem component={Link} to='/profile'>Profile</MenuItem> | ||||
|         <MenuItem component={RouterLink} to='/profile'>Profile</MenuItem> | ||||
|         <MenuItem>Logout</MenuItem> | ||||
|     </Menu>); | ||||
|     const drawer_contents = (<> | ||||
|  | @ -134,17 +139,7 @@ export const Headline = (prop: { children?: React.ReactNode, navListItem?: React | |||
|             </IconButton> | ||||
|         </div> | ||||
|         <Divider /> | ||||
|             <List> | ||||
|                 <ListItem button key="Back"> | ||||
|                     <ListItemIcon> | ||||
|                         <Tooltip title="back" placement="bottom"> | ||||
|                             <ArrowBackIcon></ArrowBackIcon> | ||||
|                         </Tooltip> | ||||
|                     </ListItemIcon> | ||||
|                     <ListItemText primary="Back"></ListItemText> | ||||
|                 </ListItem> | ||||
|                 {prop.navListItem} | ||||
|             </List> | ||||
|         {prop.menu} | ||||
|     </>); | ||||
|     return (<div className={classes.root}> | ||||
|         <CssBaseline /> | ||||
|  | @ -157,9 +152,9 @@ export const Headline = (prop: { children?: React.ReactNode, navListItem?: React | |||
|                     className={classes.menuButton}> | ||||
|                     <MenuIcon></MenuIcon> | ||||
|                 </IconButton> | ||||
|                 <Typography variant="h5" noWrap className={classes.title}> | ||||
|                 <Link variant="h5" noWrap className={classes.title} color="inherit" component={RouterLink} to="/"> | ||||
|                     Ionian | ||||
|                 </Typography> | ||||
|                 </Link> | ||||
|                 <div className={classes.grow}></div> | ||||
|                 <div className={classes.search}> | ||||
|                     <div className={classes.searchIcon}> | ||||
|  | @ -187,7 +182,7 @@ export const Headline = (prop: { children?: React.ReactNode, navListItem?: React | |||
|         <nav> | ||||
|             <Hidden smUp implementation="css"> | ||||
|                 <Drawer variant="temporary" anchor='left' open={v} onClose={toggleV} | ||||
|                     classes={{paper: classes.drawerPaper}}> | ||||
|                     classes={{ paper: classes.drawerPaper }}> | ||||
|                     {drawer_contents} | ||||
|                 </Drawer> | ||||
|             </Hidden> | ||||
|  | @ -1,3 +1,6 @@ | |||
| export * from './contentinfo'; | ||||
| export * from './loading'; | ||||
| export * from './tagchip'; | ||||
| export * from './navlist'; | ||||
| export * from './galleryinfo'; | ||||
| export * from './headline'; | ||||
							
								
								
									
										21
									
								
								src/client/component/navlist.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/client/component/navlist.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| import {List, ListItem, ListItemIcon, Tooltip, ListItemText} from '@material-ui/core'; | ||||
| import React from 'react'; | ||||
| import {Link as RouterLink} from 'react-router-dom'; | ||||
| import {LocationDescriptorObject} from 'history'; | ||||
| 
 | ||||
| export const NavItem = (props:{name:string,to:string, icon:React.ReactElement<any,any>})=>{ | ||||
|     return (<ListItem button key={props.name} component={RouterLink} to={props.to}> | ||||
|     <ListItemIcon> | ||||
|         <Tooltip title={props.name.toLocaleLowerCase()} placement="bottom"> | ||||
|             {props.icon} | ||||
|         </Tooltip> | ||||
|     </ListItemIcon> | ||||
|     <ListItemText primary={props.name}></ListItemText> | ||||
| </ListItem>); | ||||
| } | ||||
| 
 | ||||
| export const NavList = (props: {children?:React.ReactNode})=>{ | ||||
|     return (<List> | ||||
|             {props.children} | ||||
|         </List>); | ||||
| } | ||||
|  | @ -1,10 +1,11 @@ | |||
| import React, { useState, useEffect } from 'react'; | ||||
| import { Redirect, Route, Switch, useHistory, useRouteMatch, match as MatchType, Link as RouterLink } 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 { LoadingCircle } from '../component/loading'; | ||||
| import { Link, Paper, makeStyles, Theme, Box, useTheme, Typography } from '@material-ui/core'; | ||||
| import {ArrowBack as ArrowBackIcon } from '@material-ui/icons'; | ||||
| import { MangaReader } from './reader/manga'; | ||||
| import { ContentInfo } from '../component/mod'; | ||||
| import { ContentInfo, Headline, NavItem, NavList } from '../component/mod'; | ||||
| 
 | ||||
| export const makeContentInfoUrl = (id: number) => `/doc/${id}`; | ||||
| export const makeMangaReaderUrl = (id: number) => `/doc/${id}/reader`; | ||||
|  | @ -15,39 +16,65 @@ type ContentState = { | |||
| } | ||||
| 
 | ||||
| export const ContentAbout = (prop: { match: MatchType }) => { | ||||
|     const match = useRouteMatch("/doc/:id"); | ||||
|     const match = useRouteMatch<{id:string}>("/doc/:id"); | ||||
|     if (match == null) { | ||||
|         throw new Error("unreachable"); | ||||
|     } | ||||
|     const m = /\/doc\/(\d+)/.exec(match.url); | ||||
|     const id = m !== null ? Number.parseInt(m[1]) : NaN; | ||||
|     const id = Number.parseInt(match.params['id']); | ||||
|     const [info, setInfo] = useState<ContentState>({ content: undefined, notfound:false }); | ||||
|     const location = useLocation(); | ||||
|     console.log("state : "+location.state); | ||||
|     const menu_list = ( | ||||
|         <NavList> | ||||
|             <NavItem name="Back" to="/" icon={<ArrowBackIcon/>}></NavItem> | ||||
|         </NavList> | ||||
|     ); | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         (async () => { | ||||
|             console.log("mount content about"); | ||||
|             if (!isNaN(id)) { | ||||
|                 const c = await ContentAccessor.findById(id); | ||||
|                 setInfo({ content: c, notfound: c === undefined }); | ||||
|             } | ||||
|         })() | ||||
|         return ()=>{console.log("unmount content about")} | ||||
|     }, []); | ||||
|     if (isNaN(id)) { | ||||
|         return (<Typography variant='h2'>Oops. Invalid ID</Typography>) | ||||
|         return ( | ||||
|             <Headline menu={menu_list}> | ||||
|                 <Typography variant='h2'>Oops. Invalid ID</Typography> | ||||
|             </Headline> | ||||
|         ); | ||||
|     } | ||||
|     else if(info.notfound){ | ||||
|         return (<Typography variant='h2'>Content has been removed.</Typography>) | ||||
|         return ( | ||||
|             <Headline menu={menu_list}> | ||||
|                 <Typography variant='h2'>Content has been removed.</Typography> | ||||
|             </Headline> | ||||
|         ) | ||||
|     } | ||||
|     else if (info.content === undefined) { | ||||
|         return (<LoadingCircle />); | ||||
|         return (<Headline menu={menu_list}> | ||||
|             <LoadingCircle /> | ||||
|         </Headline> | ||||
|         ); | ||||
|     } | ||||
|     else return (<Switch> | ||||
|         <Route exact path={`${prop.match.path}/:id`}> | ||||
|             <Headline menu={menu_list}> | ||||
|                 <ContentInfo content={info.content}></ContentInfo> | ||||
|             </Headline> | ||||
|         </Route> | ||||
|         <Route exact path={`${prop.match.path}/:id/reader`}> | ||||
|             <Headline menu={menu_list}> | ||||
|                 <MangaReader content={info.content}></MangaReader> | ||||
|             </Headline> | ||||
|         </Route> | ||||
|         <Route> | ||||
|             <Headline menu={menu_list}> | ||||
|                 <div>404 Not Found invalid url : {prop.match.path}</div> | ||||
|             </Headline> | ||||
|         </Route> | ||||
|     </Switch>); | ||||
| } | ||||
|  | @ -1,108 +1,14 @@ | |||
| import { Box, Paper, Link, useMediaQuery } from '@material-ui/core'; | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import ContentAccessor,{makeThumbnailUrl, QueryListOption, Content} from '../accessor/contents'; | ||||
| import {useTheme, makeStyles, Theme} from '@material-ui/core/styles'; | ||||
| import {Link as RouterLink} from 'react-router-dom'; | ||||
| import {makeContentInfoUrl} from './contentinfo'; | ||||
| import { LoadingCircle } from '../component/loading'; | ||||
| import {ThumbnailContainer} from './reader/reader'; | ||||
| import {TagChip} from '../component/tagchip'; | ||||
| import React from 'react'; | ||||
| import { NavList, NavItem, Headline } from '../component/mod'; | ||||
| import {ArrowBack as ArrowBackIcon} from '@material-ui/icons'; | ||||
| import {GalleryInfo} from '../component/mod'; | ||||
| 
 | ||||
| const useStyles = makeStyles((theme:Theme)=>({ | ||||
|     root:{ | ||||
|         display:"grid", | ||||
|         gridGap: theme.spacing(4), | ||||
|     }, | ||||
|     anchor_thumbnail:{ | ||||
|         background: '#272733', | ||||
|         display: 'flex', | ||||
|         alignItems: 'center', | ||||
|         justifyContent: 'center', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             width: theme.spacing(25), | ||||
|             height: theme.spacing(25), | ||||
|         } | ||||
|     }, | ||||
|     contentPaper:{ | ||||
|         display:'flex', | ||||
|         flexDirection: 'column', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             height:200, | ||||
|             flexDirection: 'row', | ||||
|         }, | ||||
|     }, | ||||
|     content_thumnail: { | ||||
|         maxWidth: '100%', | ||||
|         maxHeight: '100%', | ||||
|     }, | ||||
|     content_info:{ | ||||
|         padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`, | ||||
|         width: '100%', | ||||
|         display: 'flex', | ||||
|         flexDirection: 'column', | ||||
|     }, | ||||
|     content_info_title:{ | ||||
|         marginLeft:theme.spacing(2), | ||||
|     }, | ||||
|     tag_list:{ | ||||
|         display:'none', | ||||
|         [theme.breakpoints.up("sm")]:{ | ||||
|             display: 'flex', | ||||
|             justifyContent: 'flex-start', | ||||
|             flexWrap: 'wrap', | ||||
|             overflowY: 'hidden', | ||||
|             '& > *': { | ||||
|                 margin: theme.spacing(0.5), | ||||
|             }, | ||||
|         }, | ||||
|     }, | ||||
| })); | ||||
| export const Gallery = ()=>{ | ||||
|     const menu_list = (<NavList> | ||||
|         <NavItem name="Back" to="" icon={<ArrowBackIcon></ArrowBackIcon>}></NavItem> | ||||
|     </NavList>); | ||||
| 
 | ||||
| export type GalleryProp = { | ||||
|     option?:QueryListOption; | ||||
| }; | ||||
| type GalleryState = { | ||||
|     content:Content[]|undefined; | ||||
| } | ||||
| 
 | ||||
| export const Gallery = (props: GalleryProp)=>{ | ||||
|     const [state,setState]= useState<GalleryState>({content:undefined}); | ||||
|     useEffect(()=>{ | ||||
|         (async ()=>{ | ||||
|             const c = await ContentAccessor.findList(props.option); | ||||
|             setState({content:c}); | ||||
|         })() | ||||
|     },[props.option]); | ||||
|     const num = 1; | ||||
|     const classes = useStyles(); | ||||
|     const theme = useTheme(); | ||||
|     const isMobile = !useMediaQuery(theme.breakpoints.up("sm")); | ||||
|         if(state.content === undefined){ | ||||
|             return (<LoadingCircle/>); | ||||
|         } | ||||
|         else{ | ||||
|             return (<div className={classes.root}>{ | ||||
|                 state.content.map(x=>{ | ||||
|                     const thumbnail_url = makeThumbnailUrl(x); | ||||
|                     return (<Paper key={x.id} elevation={4} className={classes.contentPaper}> | ||||
|                         <Link className={classes.anchor_thumbnail} | ||||
|                              component={RouterLink} to={makeContentInfoUrl(x.id)}> | ||||
|                             <ThumbnailContainer content={x} className={classes.content_thumnail}></ThumbnailContainer> | ||||
|                         </Link> | ||||
|                         <Box className={classes.content_info}> | ||||
|                             <Link component={RouterLink} to={makeContentInfoUrl(x.id)} variant="h5" color="inherit" | ||||
|                                 className={classes.content_info_title}> | ||||
|                                 {x.title} | ||||
|                             </Link> | ||||
|                             <Box className={classes.tag_list}> | ||||
|                                 {x.tags.map(x=>{ | ||||
|                                     return (<TagChip key={x} label={x} clickable={true} tagname={x} size="small"></TagChip>); | ||||
|                             })} | ||||
|                             </Box> | ||||
|                         </Box> | ||||
|                     </Paper>); | ||||
|                 }) | ||||
|                 } | ||||
|                 </div>); | ||||
|         } | ||||
|     return (<Headline menu={menu_list}> | ||||
|         <GalleryInfo></GalleryInfo> | ||||
|     </Headline>) | ||||
| } | ||||
							
								
								
									
										2
									
								
								src/client/page/mod.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/client/page/mod.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| export * from './contentinfo'; | ||||
| export * from './gallery'; | ||||
		Loading…
	
	Add table
		
		Reference in a new issue