Add appbar
This commit is contained in:
parent
2e0c0dafe4
commit
3ac8e31b7f
|
@ -65,9 +65,9 @@ services:
|
|||
POSTGRES_USER: picsur
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
- picsur-data:/var/lib/postgresql/data
|
||||
volumes:
|
||||
db-data:
|
||||
picsur-data:
|
||||
```
|
||||
|
||||
## Api
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const scopedcss = require('craco-plugin-scoped-css');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
|
@ -17,7 +16,7 @@ module.exports = {
|
|||
|
||||
port: 3300,
|
||||
liveReload: true,
|
||||
hot: true,
|
||||
hot: false,
|
||||
open: false,
|
||||
},
|
||||
plugins: [
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.contentwindow {
|
||||
width: 85vw;
|
||||
height: 80vh;
|
||||
margin: auto;
|
||||
border-radius: 20px;
|
||||
height: 100%;
|
||||
|
||||
border-style: solid;
|
||||
border-width: 5px;
|
||||
|
|
|
@ -4,6 +4,9 @@ import Centered from './components/centered/centered';
|
|||
import './app.scss';
|
||||
import AppRouter from './routes/router';
|
||||
import { SnackbarProvider } from 'notistack';
|
||||
import Header from './components/header/header';
|
||||
import { Container } from '@mui/material';
|
||||
import Footer from './components/footer/footer';
|
||||
|
||||
export default function App() {
|
||||
const darkTheme = createTheme({
|
||||
|
@ -15,11 +18,12 @@ export default function App() {
|
|||
return (
|
||||
<ThemeProvider theme={darkTheme}>
|
||||
<CssBaseline />
|
||||
|
||||
<SnackbarProvider maxSnack={3}>
|
||||
<Centered fullScreen={true}>
|
||||
<Header />
|
||||
<Container className="main-container">
|
||||
<AppRouter />
|
||||
</Centered>
|
||||
</Container>
|
||||
<Footer />
|
||||
</SnackbarProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
|
|
@ -5,14 +5,7 @@
|
|||
align-items: center;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.centered-screen {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.centered-normal {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,13 @@ import './centered.scoped.scss';
|
|||
type PropsType = React.DetailedHTMLProps<
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & { fullScreen?: boolean };
|
||||
>;
|
||||
|
||||
const Centered = forwardRef(
|
||||
(props: PropsType, ref: ForwardedRef<HTMLDivElement>) => {
|
||||
let clss = 'centered';
|
||||
if (props.fullScreen) {
|
||||
clss += ' centered-screen';
|
||||
} else {
|
||||
clss += ' centered-normal';
|
||||
}
|
||||
|
||||
let filteredProps = { ...props };
|
||||
delete filteredProps.fullScreen;
|
||||
|
||||
return <div className={clss} ref={ref} {...filteredProps} />;
|
||||
return <div className="centered" ref={ref} {...filteredProps} />;
|
||||
},
|
||||
);
|
||||
|
||||
|
|
3
frontend/src/components/footer/footer.scoped.scss
Normal file
3
frontend/src/components/footer/footer.scoped.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
.footer-container {
|
||||
margin-top: 32px;
|
||||
}
|
10
frontend/src/components/footer/footer.tsx
Normal file
10
frontend/src/components/footer/footer.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Box, Container } from '@mui/material';
|
||||
import './footer.scoped.scss';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<Box sx={{ flexGrow: 0 }} className="footer">
|
||||
<Container className="footer-container"></Container>
|
||||
</Box>
|
||||
);
|
||||
}
|
14
frontend/src/components/header/header.scoped.scss
Normal file
14
frontend/src/components/header/header.scoped.scss
Normal file
|
@ -0,0 +1,14 @@
|
|||
.svg-logo {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
border-radius: 20%;
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 32px;
|
||||
}
|
34
frontend/src/components/header/header.tsx
Normal file
34
frontend/src/components/header/header.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { AppBar, Toolbar, IconButton, Typography, Button } from '@mui/material';
|
||||
import { Box } from '@mui/system';
|
||||
import { Link } from 'react-router-dom';
|
||||
import './header.scoped.scss';
|
||||
|
||||
export default function Header() {
|
||||
return (
|
||||
<Box sx={{ flexGrow: 0 }} className="header">
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
<Link to="/">
|
||||
<Box
|
||||
component="div"
|
||||
sx={{ mr: 2, display: { xs: 'none', md: 'flex' } }}
|
||||
>
|
||||
<img
|
||||
src="/image/logo/picsur.svg"
|
||||
alt="Picsur"
|
||||
className="svg-logo"
|
||||
/>
|
||||
</Box>
|
||||
</Link>
|
||||
|
||||
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
|
||||
<Link to="/" className="text-link">
|
||||
Picsur
|
||||
</Link>
|
||||
</Typography>
|
||||
<Button color="inherit">Login</Button>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
</Box>
|
||||
);
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
.uploadedimage {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
height: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { Button, Grid, IconButton, TextField } from '@mui/material';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Container,
|
||||
Grid,
|
||||
IconButton,
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
|
@ -19,31 +26,11 @@ export default function ViewView() {
|
|||
const { enqueueSnackbar } = useSnackbar();
|
||||
const hash = useParams().hash ?? '';
|
||||
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const gridRef = useRef<HTMLDivElement>(null);
|
||||
const imgRef = useRef<HTMLImageElement>(null);
|
||||
|
||||
const resizeImage = () => {
|
||||
if (imgRef.current) imgRef.current.style.height = '0';
|
||||
|
||||
const contentHeight = contentRef.current?.offsetHeight ?? 0;
|
||||
const gridHeight = gridRef.current?.offsetHeight ?? 0;
|
||||
const newImgHeight = contentHeight - gridHeight;
|
||||
|
||||
if (imgRef.current) imgRef.current.style.height = newImgHeight + 'px';
|
||||
};
|
||||
|
||||
const effectHandler = async () => {
|
||||
if (!isHash(hash, 'sha256')) return exitError('Invalid image link');
|
||||
|
||||
const imageMeta = await ImagesApi.I.GetImageMeta(hash);
|
||||
if (HasFailed(imageMeta)) return exitError(imageMeta.getReason());
|
||||
|
||||
resizeImage();
|
||||
const resizeImageDebounced = Debounce(resizeImage, 100);
|
||||
window.addEventListener('resize', resizeImageDebounced);
|
||||
|
||||
return () => window.removeEventListener('resize', resizeImageDebounced);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -77,18 +64,15 @@ export default function ViewView() {
|
|||
|
||||
return (
|
||||
<section className="contentwindow">
|
||||
<Centered ref={contentRef}>
|
||||
<Grid container spacing={2} ref={gridRef}>
|
||||
<Centered>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<h1>Uploaded Image</h1>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<img
|
||||
className="uploadedimage"
|
||||
alt="Uploaded"
|
||||
src={imageURL}
|
||||
ref={imgRef}
|
||||
/>
|
||||
<Container maxWidth="sm">
|
||||
<img className="uploadedimage" alt="Uploaded" src={imageURL} />
|
||||
</Container>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{createCopyField('Image URL', imageURL)}
|
||||
|
|
Loading…
Reference in a new issue