1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-24 21:15:51 +01:00

chore: website drawer for navigation (#1940)

* feat(website): add drawer navigation

* chore: create index by language

* Update Header.tsx
This commit is contained in:
Juan Picado 2020-09-13 10:13:11 +02:00
parent d460a2c5da
commit 1e48f1c077
14 changed files with 323 additions and 160 deletions

@ -58,7 +58,7 @@
"camelcase": "off",
"guard-for-in": "error",
"new-cap": "error",
"max-len": ["warn", 180],
"max-len": ["warn", 160],
"no-console": ["error", { "allow": ["warn"] }],
"no-constant-condition": "error",
"no-debugger": "error",

16
pnpm-lock.yaml generated

@ -722,7 +722,7 @@ importers:
'@mikaelkristiansson/domready': 1.0.10
'@reach/router': 1.3.4_react-dom@16.13.1+react@16.13.1
babel-preset-gatsby: 0.4.12
clsx: 1.1.1
classnames: 2.2.6
emotion-theming: 10.0.27_c989b1aa057905c7a8b69bf973f55a19
event-source-polyfill: 1.0.17
fontsource-roboto: 2.2.6
@ -774,7 +774,7 @@ importers:
'@reach/router': 1.3.4
'@types/react-helmet': ^5.0.16
babel-preset-gatsby: ^0.4.12
clsx: ^1.1.1
classnames: ^2.2.6
emotion-theming: 10.0.27
event-source-polyfill: ^1.0.17
fontsource-roboto: ^2.2.6
@ -1311,8 +1311,8 @@ packages:
dependencies:
'@babel/core': 7.10.5
'@babel/helper-plugin-utils': 7.10.4
'@babel/plugin-syntax-object-rest-spread': 7.8.3
'@babel/plugin-transform-parameters': 7.10.5
'@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.10.5
'@babel/plugin-transform-parameters': 7.10.5_@babel+core@7.10.5
peerDependencies:
'@babel/core': ^7.0.0-0
resolution:
@ -1610,6 +1610,7 @@ packages:
/@babel/plugin-syntax-object-rest-spread/7.8.3:
dependencies:
'@babel/helper-plugin-utils': 7.10.4
dev: false
peerDependencies:
'@babel/core': ^7.0.0-0
resolution:
@ -1618,7 +1619,6 @@ packages:
dependencies:
'@babel/core': 7.10.5
'@babel/helper-plugin-utils': 7.10.4
dev: true
peerDependencies:
'@babel/core': ^7.0.0-0
resolution:
@ -2106,6 +2106,7 @@ packages:
dependencies:
'@babel/helper-get-function-arity': 7.10.4
'@babel/helper-plugin-utils': 7.10.4
dev: false
peerDependencies:
'@babel/core': ^7.0.0-0
resolution:
@ -2115,7 +2116,6 @@ packages:
'@babel/core': 7.10.5
'@babel/helper-get-function-arity': 7.10.4
'@babel/helper-plugin-utils': 7.10.4
dev: true
peerDependencies:
'@babel/core': ^7.0.0-0
resolution:
@ -7235,6 +7235,10 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
/classnames/2.2.6:
dev: false
resolution:
integrity: sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
/clean-css/4.2.3:
dependencies:
source-map: 0.6.1

@ -17,6 +17,7 @@ exports.onCreateWebpackConfig = ({ stage, actions }) => {
// You can delete this file if you're not using it
const path = require('path');
const docPageTemplate = path.resolve('src/templates/docPage.tsx');
const frontPageTemplate = path.resolve('src/templates/frontpage.tsx');
const sideBar = require('./config/sidebar.json');
exports.createPages = async ({ graphql, actions }) => {
@ -42,6 +43,9 @@ exports.createPages = async ({ graphql, actions }) => {
const posts = result.data.allMarkdownRemark.edges;
const idTitleMap = {};
const languages = [];
// create documentation pages
posts.forEach(({ node }) => {
console.log('-node.fileAbsolutePath-', node.frontmatter);
const parsedPath = path.parse(node.fileAbsolutePath);
@ -50,9 +54,10 @@ exports.createPages = async ({ graphql, actions }) => {
const name = parsedPath.name;
const title = node.frontmatter.title;
const lng = parsedPath.dir.match('translated_docs') ? parsedPath.dir.split('/').pop() : 'en';
console.log('-lng', lng);
console.log('-markDownId', markDownId);
console.log('-title', title);
if (!languages.includes(lng)) {
languages.push(lng);
}
if (!idTitleMap[lng]) {
idTitleMap[lng] = {};
}
@ -65,4 +70,13 @@ exports.createPages = async ({ graphql, actions }) => {
context: { id, lng, sideBar, title, idTitleMap, markDownId },
});
});
// create index pages
languages.map((language) => {
createPage({
path: language === 'en' ? '/' : `/${language}/index.html`,
component: frontPageTemplate,
context: { id: '', lng: language, sideBar, title: '', idTitleMap, markDownId: '/' },
});
});
};

@ -15,7 +15,7 @@
"@mikaelkristiansson/domready": "1.0.10",
"@reach/router": "1.3.4",
"babel-preset-gatsby": "^0.4.12",
"clsx": "^1.1.1",
"classnames": "^2.2.6",
"emotion-theming": "10.0.27",
"event-source-polyfill": "^1.0.17",
"fontsource-roboto": "^2.2.6",

@ -0,0 +1,55 @@
import React, { useState, FunctionComponent } from 'react';
import Drawer from '@material-ui/core/Drawer';
import SwipeableDrawer from '@material-ui/core/SwipeableDrawer';
import Hidden from '@material-ui/core/Hidden';
import SideBar from '../SideBar/SideBar';
import { usePageContext } from '../PageContext';
export type Props = {
className: string;
isPermanent: boolean;
open: boolean;
onClose: any;
classes: any;
onOpen: any;
};
const DrawerSideBar = () => {
const { currentPage, idTitleMap, language, sideBarConfiguration } = usePageContext();
return <SideBar lng={language} sideBarConf={sideBarConfiguration} currentPage={currentPage} idTitleMap={idTitleMap} />;
};
const AppDrawer: FunctionComponent<Props> = ({ className, isPermanent, onClose, onOpen, open, classes }) => {
return (
<nav className={className}>
<Hidden lgUp={isPermanent} implementation="js">
<SwipeableDrawer
variant="temporary"
onClose={onClose}
onOpen={onOpen}
open={open}
ModalProps={{
keepMounted: true,
}}>
<DrawerSideBar />
</SwipeableDrawer>
</Hidden>
{!isPermanent ? null : (
<Hidden mdDown implementation="css">
<Drawer
classes={{
paper: classes.paper,
}}
variant="permanent"
open>
<DrawerSideBar />
</Drawer>
</Hidden>
)}
</nav>
);
};
export { AppDrawer };

@ -0,0 +1 @@
export { AppDrawer as default, Props } from './AppDrawer';

@ -1,27 +1,48 @@
import React, { FunctionComponent, MouseEventHandler } from 'react';
import { Link } from 'gatsby';
import cx from 'classnames';
import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import VerdaccioWhiteLogo from './VerdaccioWhiteLogo';
export type Props = {
onClickOpen: MouseEventHandler;
isPermanent: boolean;
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
appBar: {
zIndex: theme.zIndex.drawer + 1,
// zIndex: theme.zIndex.drawer + 1,
backgroundColor: '#FFF',
},
appBarShift: {
[theme.breakpoints.up('lg')]: {
width: 'calc(100% - 299px)',
},
},
drawer: {
[theme.breakpoints.up('lg')]: {
flexShrink: 0,
width: 300,
},
},
navIconHide: {
color: '#000',
[theme.breakpoints.up('lg')]: {
display: 'none',
},
},
})
);
const Header: FunctionComponent<Props> = ({ onClickOpen }) => {
const Header: FunctionComponent<Props> = ({ onClickOpen, isPermanent }) => {
// const {
// site: {
// siteMetadata: { siteName },
@ -38,8 +59,15 @@ const Header: FunctionComponent<Props> = ({ onClickOpen }) => {
const classes = useStyles();
return (
<AppBar position="fixed" onClick={onClickOpen} className={classes.appBar}>
<AppBar
onClick={onClickOpen}
className={cx(classes.appBar, {
[classes.appBarShift]: isPermanent,
})}>
<Toolbar>
<IconButton edge="start" color="inherit" onClick={onClickOpen} className={classes.navIconHide}>
<MenuIcon />
</IconButton>
<Typography component="h2" variant="h5">
<Link title="Home" to="/">
<VerdaccioWhiteLogo width="30px" />

@ -1,14 +1,15 @@
import React, { FC, Fragment } from 'react';
import React, { FunctionComponent, useCallback } from 'react';
import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import '../css/code.css';
import CssBaseline from '@material-ui/core/CssBaseline';
import PropTypes from 'prop-types';
import Footer from './Footer';
import Header from './Header';
import { AppDrawer } from './AppDrawer/AppDrawer';
import { usePageContext } from './PageContext';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -26,14 +27,41 @@ const useStyles = makeStyles((theme: Theme) =>
})
);
const Layout: FC = ({ children }) => {
const classes = useStyles();
export type Props = {
classes: any;
isPermanent: boolean;
};
const Layout: FunctionComponent<Props> = ({ children, classes, isPermanent = true }) => {
const layoutClasses = useStyles();
const { isDrawerOpen, setIsDrawerOpen } = usePageContext();
const clickOpenMenuHandler = useCallback(() => {
setIsDrawerOpen(true);
}, [isDrawerOpen]);
const clickOnOpenDrawerHandler = useCallback(() => {
// no defined yet
}, [isDrawerOpen]);
const clickOnCloseDrawerHandler = useCallback(() => {
// no defined yet
setIsDrawerOpen(false);
}, [isDrawerOpen]);
return (
<div className={classes.root}>
<div className={layoutClasses.root}>
<CssBaseline />
<Header onClickOpen={() => {}} />
<Container component="main" className={classes.main}>
<Header onClickOpen={clickOpenMenuHandler} isPermanent={isPermanent} />
<AppDrawer
className={'paper'}
isPermanent={isPermanent}
open={isDrawerOpen}
onClose={clickOnCloseDrawerHandler}
classes={classes}
onOpen={clickOnOpenDrawerHandler}
/>
<Container component="main" className={layoutClasses.main}>
{children}
<Footer />
</Container>
@ -41,8 +69,4 @@ const Layout: FC = ({ children }) => {
);
};
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;

@ -0,0 +1,40 @@
import React, { useContext, FunctionComponent, useState } from 'react';
type PageContextProviderProps = {
language: string;
idTitleMap: any;
isDrawerOpen: boolean;
setIsDrawerOpen: Function;
sideBarConfiguration: any;
currentPage: string | null;
};
const defaultContextProps = {
language: 'en',
isDrawerOpen: false,
idTitleMap: {},
setIsDrawerOpen: () => {},
sideBarConfiguration: {},
currentPage: null,
};
const PageContext = React.createContext<PageContextProviderProps>(defaultContextProps);
type Props = {
language: string;
idTitleMap: any;
currentPage: string;
sideBarConfiguration: any;
};
const PageContextProvider: FunctionComponent<Props> = ({ children, language, idTitleMap, sideBarConfiguration, currentPage }) => {
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
return (
<PageContext.Provider value={{ language, idTitleMap, sideBarConfiguration, currentPage, isDrawerOpen, setIsDrawerOpen }}>{children}</PageContext.Provider>
);
};
const usePageContext = () => useContext(PageContext);
export { PageContextProvider, usePageContext };

@ -0,0 +1 @@
export { PageContextProvider, usePageContext } from './PageContext';

@ -10,13 +10,12 @@ import Collapse from '@material-ui/core/Collapse';
export type SideBarProps = {
lng: string;
sideBarConf: any;
currentPage: string;
currentPage: string | null;
idTitleMap: any;
};
const SideBar: FunctionComponent<SideBarProps> = (props) => {
const { sideBarConf, idTitleMap, currentPage, lng } = props;
console.log('----->', Object.keys(sideBarConf.docs));
const sections = Object.keys(sideBarConf.docs);
const titles = idTitleMap[lng];

@ -1,119 +0,0 @@
import React from 'react';
import { Link } from 'gatsby';
import { Tweet } from 'react-twitter-widgets';
import 'fontsource-roboto';
import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Layout from '../components/Layout';
import Seo from '../components/Seo';
import CopyToClipBoard from '../components/CopyToClipBoard';
const Tweets = ['1001297542779424768', '1002609907370250241', '951427300070916096', '1002153128140136448', '1169571193550192641', '1168280372800557063'];
const useStyles = makeStyles((theme) => ({
icon: {
marginRight: theme.spacing(2),
},
heroContent: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(12, 0, 6),
},
heroButtons: {
marginTop: theme.spacing(4),
},
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8),
},
card: {
height: '100%',
display: 'flex',
flexDirection: 'column',
},
cardMedia: {
paddingTop: '56.25%', // 16:9
},
cardContent: {
flexGrow: 1,
},
footer: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(6),
},
}));
const IndexPage = () => {
const classes = useStyles();
return (
<Layout>
<Seo />
<div className={classes.heroContent}>
<Container maxWidth="sm">
<Typography component="h1" variant="h2" align="center" color="textPrimary" gutterBottom>
Verdaccio
</Typography>
<Typography variant="h5" align="center" color="textSecondary" paragraph>
A lightweight open source private npm proxy registry
</Typography>
<div className={classes.heroButtons}>
<Grid container spacing={2} justify="center">
<Grid item>
<Link title="getting-started" to="/docs/en/what-is-verdaccio.html">
<Button variant="contained" color="primary">
Get Started
</Button>
</Link>
</Grid>
<Grid item>
<a href="https://github.com/verdaccio" target="_blank" rel="noopener noreferrer">
<Button variant="outlined" color="primary">
GitHub
</Button>
</a>
</Grid>
<Grid item>
<Button variant="outlined" color="primary">
<Link title="Documents" to="/docs/en/contribute.html">
Contribute
</Link>
</Button>
</Grid>
</Grid>
<Grid container spacing={2} justify="center">
<CopyToClipBoard text="npm i -g verdaccio" />
</Grid>
</div>
</Container>
</div>
<Container className={classes.cardGrid} maxWidth="md">
<Grid container spacing={4}>
{Tweets.map((tweetId) => (
<Card key={tweetId} variant="outlined" className={classes.card}>
<CardContent className={classes.cardContent}>
<Tweet
tweetId={tweetId}
options={{
height: '300',
// theme: 'dark',
conversation: 'none',
cards: 'hidden',
}}
/>
</CardContent>
</Card>
))}
</Grid>
</Container>
</Layout>
);
};
export default IndexPage;

@ -10,6 +10,7 @@ import Typography from '@material-ui/core/Typography';
import SideBar from '../components/SideBar/SideBar';
import './docPage.css';
import { PageContextProvider } from '../components/PageContext';
const drawerWidth = 350;
@ -46,27 +47,19 @@ const DocPage = (props: any) => {
const title = markdownRemark.frontmatter.title;
const html = markdownRemark.html;
const { lng, sideBar, name, idTitleMap, markDownId } = props.pageContext;
console.log(idTitleMap[lng]);
console.log(idTitleMap[lng], name);
return (
<Layout>
<h1>{title}</h1>
<div className={classes.container}>
<Drawer
className={classes.drawer}
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}>
<SideBar lng={lng} sideBarConf={sideBar} currentPage={name} idTitleMap={idTitleMap} />
</Drawer>
<PageContextProvider language={lng} idTitleMap={idTitleMap} currentPage={markDownId} sideBarConfiguration={sideBar}>
<Layout classes={{}} isPermanent>
<h1>{title}</h1>
<main className={classes.content}>
<Typography component="h4" variant="h5" color="textPrimary" gutterBottom>
{idTitleMap[lng][markDownId]}
</Typography>
<Typography variant="body1" dangerouslySetInnerHTML={{ __html: html }}></Typography>
</main>
</div>
</Layout>
</Layout>
</PageContextProvider>
);
};

@ -0,0 +1,123 @@
import React from 'react';
import { Link } from 'gatsby';
import { Tweet } from 'react-twitter-widgets';
import 'fontsource-roboto';
import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Layout from '../components/Layout';
import Seo from '../components/Seo';
import CopyToClipBoard from '../components/CopyToClipBoard';
import { PageContextProvider } from '../components/PageContext';
const Tweets = ['1001297542779424768', '1002609907370250241', '951427300070916096', '1002153128140136448', '1169571193550192641', '1168280372800557063'];
const useStyles = makeStyles((theme) => ({
icon: {
marginRight: theme.spacing(2),
},
heroContent: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(12, 0, 6),
},
heroButtons: {
marginTop: theme.spacing(4),
},
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8),
},
card: {
height: '100%',
display: 'flex',
flexDirection: 'column',
},
cardMedia: {
paddingTop: '56.25%', // 16:9
},
cardContent: {
flexGrow: 1,
},
footer: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(6),
},
}));
const IndexPage = (props: any) => {
const classes = useStyles();
const { lng, sideBar, idTitleMap, markDownId } = props.pageContext;
return (
<PageContextProvider language={lng} idTitleMap={idTitleMap} currentPage={markDownId} sideBarConfiguration={sideBar}>
<Layout isPermanent={false} classes={{}}>
<Seo />
<div className={classes.heroContent}>
<Container maxWidth="sm">
<Typography component="h1" variant="h2" align="center" color="textPrimary" gutterBottom>
Verdaccio
</Typography>
<Typography variant="h5" align="center" color="textSecondary" paragraph>
A lightweight open source private npm proxy registry
</Typography>
<div className={classes.heroButtons}>
<Grid container spacing={2} justify="center">
<Grid item>
<Link title="getting-started" to="/docs/en/what-is-verdaccio.html">
<Button variant="contained" color="primary">
Get Started
</Button>
</Link>
</Grid>
<Grid item>
<a href="https://github.com/verdaccio" target="_blank" rel="noopener noreferrer">
<Button variant="outlined" color="primary">
GitHub
</Button>
</a>
</Grid>
<Grid item>
<Button variant="outlined" color="primary">
<Link title="Documents" to="/docs/en/contribute.html">
Contribute
</Link>
</Button>
</Grid>
</Grid>
<Grid container spacing={2} justify="center">
<CopyToClipBoard text="npm i -g verdaccio" />
</Grid>
</div>
</Container>
</div>
<Container className={classes.cardGrid} maxWidth="md">
<Grid container spacing={4}>
{Tweets.map((tweetId) => (
<Card key={tweetId} variant="outlined" className={classes.card}>
<CardContent className={classes.cardContent}>
<Tweet
tweetId={tweetId}
options={{
height: '300',
// theme: 'dark',
conversation: 'none',
cards: 'hidden',
}}
/>
</CardContent>
</Card>
))}
</Grid>
</Container>
</Layout>
</PageContextProvider>
);
};
export default IndexPage;