Merge pull request #600 from GlancingMind/upstream-improve-navigation

WebUI: Improve navigation
This commit is contained in:
Michael Muré 2021-03-21 21:31:14 +01:00 committed by GitHub
commit 52df5a1f11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 210 additions and 22 deletions

View File

@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1024 1024">
<defs>
<path id="b" d="M512.169916 1006.61442c-59.127025 0-118.268018-11.781213-172.799806-34.617561-54.406082-22.780496-104.066777-56.504427-145.315673-98.654977-20.922999-21.380714-39.670593-44.876809-55.890107-70.010056-17.752424-27.503453-33.154852-57.048981-43.3125626-88.22468-22.4244822-68.819718-19.4215151-144.704671 8.7854246-211.391554 26.454045-62.532915 73.778712-115.431419 133.345707-148.122094 7.140776-3.916598 14.438685-7.546956 21.869283-10.877111 1.581795-22.420951 7.259498-44.632458 15.35005-65.555887 8.062618-20.853613 18.635855-41.190599 32.313323-58.926992l-45.425115-45.365511c-25.284285 1.612716-50.236847-9.407515-66.183999-29.060318-15.870332-19.558553-21.457247-46.1579063-14.75644-70.4463972 6.473838-23.4786418 24.027228-43.0790839 46.615826-52.1759231 23.259028-9.3656253 50.268273-6.8837172 71.435699 6.5416257 24.04818 15.2579756 38.322749 42.9953065 36.534936 71.4447456l49.377858 49.310035c38.850014-22.675774 83.39519-34.258012 128.055596-34.331317 44.660406.073305 89.205582 11.655543 128.059088 34.331317l49.374366-49.310035c-1.787813-28.4494391 12.486757-56.18677 36.534936-71.4447456 21.167427-13.4253429 48.176671-15.907251 71.435699-6.5416257 22.588598 9.0968392 40.138497 28.6972813 46.615827 52.1759231 6.700807 24.2919816 1.113891 50.8878442-14.756441 70.4463972-15.947152 19.652803-40.899714 30.673034-66.18749 29.060318l-45.421623 45.365511c13.677467 17.736393 24.250705 38.073379 32.313322 58.926992 8.090552 20.923429 13.768255 43.134936 15.350051 65.555887 7.430598 3.330155 14.731998 6.960513 21.869282 10.877111 59.566996 32.690675 106.891662 85.59267 133.345707 148.125585 28.20694 66.683392 31.213399 142.568345 8.785425 211.388063-10.157711 31.175699-25.560139 60.721227-43.312563 88.22468-16.219514 25.133247-34.967108 48.629342-55.890106 70.010056-41.252388 42.15055-90.913084 75.874481-145.315674 98.654977-54.535279 22.836348-113.67278 34.617561-172.799806 34.617561"/>
<filter id="a" width="106%" height="105.3%" x="-3%" y="-2.2%" filterUnits="objectBoundingBox">
<feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1"/>
<feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="8"/>
<feColorMatrix in="shadowBlurOuter1" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
</filter>
</defs>
<g fill="none" fill-rule="evenodd">
<g fill-rule="nonzero">
<use fill="#000" filter="url(#a)" xlink:href="#b"/>
<use fill="#FFF" xlink:href="#b"/>
</g>
<path fill="#D0021B" d="M120.388511 676.726932c4.109875 19.495721 10.395155 38.464341 18.695216 56.570751 62.793439 135.897562 197.675548 231.648253 355.628126 238.256202V392.229046l-86.684487 86.608471c2.007798 5.044104 3.14264 10.531529 3.14264 16.291232 0 18.162262-10.988764 33.751856-26.67403 40.516889v210.012716c15.685266 6.768523 26.67403 22.354627 26.67403 40.520379 0 24.368778-19.760222 44.119321-44.133141 44.119321-24.376411 0-44.136633-19.750543-44.136633-44.119321 0-18.165752 10.988765-33.751856 26.677522-40.520379V537.23741l-62.37442 62.319981c2.007797 5.040612 3.14264 10.524547 3.14264 16.280759 0 24.365287-19.760222 44.119321-44.133141 44.119321-24.376411 0-44.136633-19.754034-44.136633-44.119321 0-24.368778 19.760222-44.122812 44.136633-44.122812 5.764998 0 11.257635 1.137978 16.306809 3.148638l63.519738-63.46145c-2.004306-5.040612-3.139148-10.521056-3.139148-16.273777 0-24.368778 19.760222-44.122812 44.136633-44.122812 5.761507 0 11.254143 1.137977 16.299826 3.145147l111.375162-111.273962v-3.413933c-58.285497 1.124015-115.188232 7.857631-170.205383 19.680729-143.245022 32.174047-234.4758615 173.520637-204.117959 317.583014"/>
<path fill="#161616" d="M512.169916 150.665029c49.758467 0 95.630535 16.518128 132.511162 44.321783l82.55366-82.440542c-6.274804-15.7815846-2.786474-34.1393273 8.844786-46.4999979 10.552287-11.2122209 26.565784-16.165565 41.619029-12.8772985 14.718031 3.2184519 27.058131 14.1025443 32.114289 28.2853753 5.188848 14.5388854 2.234766 31.1547541-7.633123 43.0162511-12.102656 14.549357-32.662505 19.788941-50.271765 12.769086l-81.048685 80.939528c29.792227 30.913894 50.669832 70.474323 58.411202 114.579682-55.240628-13.338075-111.706885-21.541288-168.455979-24.511898-57.475394-3.009008-115.233625-.684183-172.272541 6.988439-31.433384 4.227273-62.643291 10.081225-93.469098 17.523459 7.737878-44.105359 28.615484-83.665788 58.404219-114.579682l-81.048686-80.939528c-15.79002 6.297274-34.181447 2.810036-46.552973-8.824563-11.219225-10.548982-16.174121-26.560955-12.884824-41.6059961 3.21946-14.7134218 14.106961-27.0496574 28.294235-32.1077234 14.54344-5.1837322 31.164513-2.2305757 43.029725 7.6342239 14.539948 12.0918845 19.784665 32.6173697 12.790545 50.2106426l82.553661 82.440542c36.884118-27.803655 82.752695-44.321783 132.511161-44.321783"/>
<path fill="#D0021B" d="M700.196272 359.235741c-55.01715-11.823099-111.916394-18.556715-170.20189-19.68422v3.413933l111.37167 111.277452c5.049175-2.007169 10.538319-3.148637 16.303318-3.148637 24.376411 0 44.136632 19.757525 44.136632 44.122812 0 5.756211-1.134842 11.233165-3.139148 16.273777l63.516246 63.46494c5.049175-2.01066 10.541812-3.148637 16.310302-3.148637 24.372919 0 44.136633 19.754034 44.136633 44.119321 0 24.368778-19.763714 44.122812-44.136633 44.122812-24.376411 0-44.136633-19.754034-44.136633-44.122812 0-5.756212 1.134842-11.240147 3.146132-16.280759l-62.377912-62.319981v208.424434c15.688757 6.765033 26.681013 22.354627 26.681013 40.52038 0 24.365287-19.760221 44.119321-44.136632 44.119321-24.372919 0-44.133141-19.754034-44.133141-44.119321 0-18.165753 10.985272-33.755347 26.670538-40.52038V535.73746c-15.685266-6.765032-26.670538-22.354627-26.670538-40.520379 0-5.759703 1.134842-11.247129 3.14264-16.287741l-86.684487-86.611963v579.32484c157.949086-6.604459 292.831195-102.35864 355.628126-238.252711 8.296569-18.109901 14.581849-37.078522 18.691724-56.570751 30.357902-144.065868-60.872937-285.408967-204.11796-317.583014"/>
</g>
<animate attributeName="opacity" attributeType="XML"
dur="5s" from="0" to="1" fill="freeze"/>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -5,6 +5,7 @@ import Layout from './components/Header';
import BugPage from './pages/bug';
import ListPage from './pages/list';
import NewBugPage from './pages/new/NewBugPage';
import NotFoundPage from './pages/notfound/NotFoundPage';
export default function App() {
return (
@ -13,6 +14,7 @@ export default function App() {
<Route path="/" exact component={ListPage} />
<Route path="/new" exact component={NewBugPage} />
<Route path="/bug/:id" exact component={BugPage} />
<Route component={NotFoundPage} />
</Switch>
</Layout>
);

View File

@ -0,0 +1,36 @@
import React from 'react';
import Button from '@material-ui/core/Button';
import { makeStyles } from '@material-ui/core/styles';
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
const useStyles = makeStyles((theme) => ({
backButton: {
position: 'sticky',
top: '80px',
backgroundColor: theme.palette.primary.dark,
color: theme.palette.primary.contrastText,
'&:hover': {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
},
},
}));
function BackToListButton() {
const classes = useStyles();
return (
<Button
variant="contained"
className={classes.backButton}
aria-label="back to issue list"
href="/"
>
<ArrowBackIcon />
Back to List
</Button>
);
}
export default BackToListButton;

View File

@ -70,7 +70,7 @@ function BugTitleForm({ bug }: Props) {
function isFormValid() {
if (issueTitleInput) {
return issueTitleInput.value.length > 0 ? true : false;
return issueTitleInput.value.length > 0;
} else {
return false;
}

View File

@ -11,7 +11,7 @@ const useStyles = makeStyles({
const PreTag = (props: React.HTMLProps<HTMLPreElement>) => {
const classes = useStyles();
return <pre className={classes.tag} {...props}></pre>;
return <pre className={classes.tag} {...props} />;
};
export default PreTag;

View File

@ -1,12 +1,15 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import AppBar from '@material-ui/core/AppBar';
import Tab, { TabProps } from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
import Toolbar from '@material-ui/core/Toolbar';
import Tooltip from '@material-ui/core/Tooltip/Tooltip';
import { makeStyles } from '@material-ui/core/styles';
import { LightSwitch } from '../../components/Themer';
import CurrentIdentity from '../CurrentIdentity/CurrentIdentity';
import { LightSwitch } from '../Themer';
const useStyles = makeStyles((theme) => ({
offset: {
@ -15,9 +18,13 @@ const useStyles = makeStyles((theme) => ({
filler: {
flexGrow: 1,
},
appBar: {
backgroundColor: theme.palette.primary.dark,
color: theme.palette.primary.contrastText,
},
appTitle: {
...theme.typography.h6,
color: 'white',
color: theme.palette.primary.contrastText,
textDecoration: 'none',
display: 'flex',
alignItems: 'center',
@ -31,18 +38,53 @@ const useStyles = makeStyles((theme) => ({
},
}));
function a11yProps(index: any) {
return {
id: `nav-tab-${index}`,
'aria-controls': `nav-tabpanel-${index}`,
};
}
const DisabledTabWithTooltip = (props: TabProps) => {
/*The span elements around disabled tabs are needed, as the tooltip
* won't be triggered by disabled elements.
* See: https://material-ui.com/components/tooltips/#disabled-elements
* This must be done in a wrapper component, otherwise the TabS component
* cannot pass it styles down to the Tab component. Resulting in (console)
* warnings. This wrapper acceps the passed down TabProps and pass it around
* the span element to the Tab component.
*/
const msg = `This feature doesn't exist yet. Come help us build it.`;
return (
<Tooltip title={msg}>
<span>
<Tab disabled {...props} />
</span>
</Tooltip>
);
};
function Header() {
const classes = useStyles();
const location = useLocation();
const [selectedTab, setTab] = React.useState(location.pathname);
const handleTabClick = (
event: React.ChangeEvent<{}>,
newTabValue: string
) => {
setTab(newTabValue);
};
return (
<>
<AppBar position="fixed" color="primary">
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<Link to="/" className={classes.appTitle}>
<img src="/logo.svg" className={classes.logo} alt="git-bug" />
<img src="/logo.svg" className={classes.logo} alt="git-bug logo" />
git-bug
</Link>
<div className={classes.filler}></div>
<div className={classes.filler} />
<div className={classes.lightSwitch}>
<LightSwitch />
</div>
@ -50,6 +92,25 @@ function Header() {
</Toolbar>
</AppBar>
<div className={classes.offset} />
<Tabs
centered
value={selectedTab}
onChange={handleTabClick}
aria-label="nav tabs"
>
<DisabledTabWithTooltip label="Code" value="/code" {...a11yProps(1)} />
<Tab label="Bugs" value="/" component={Link} to="/" {...a11yProps(2)} />
<DisabledTabWithTooltip
label="Pull Requests"
value="/pulls"
{...a11yProps(3)}
/>
<DisabledTabWithTooltip
label="Settings"
value="/settings"
{...a11yProps(4)}
/>
</Tabs>
</>
);
}

View File

@ -18,11 +18,17 @@ const useStyles = makeStyles((theme) => ({
maxWidth: 1000,
margin: 'auto',
marginTop: theme.spacing(4),
overflow: 'hidden',
},
header: {
marginLeft: theme.spacing(3) + 40,
marginRight: theme.spacing(2),
marginLeft: theme.spacing(3) + 40,
},
title: {
...theme.typography.h5,
},
id: {
...theme.typography.subtitle1,
marginLeft: theme.spacing(1),
},
container: {
display: 'flex',
@ -36,11 +42,11 @@ const useStyles = makeStyles((theme) => ({
marginRight: theme.spacing(2),
minWidth: 400,
},
sidebar: {
rightSidebar: {
marginTop: theme.spacing(2),
flex: '0 0 200px',
},
sidebarTitle: {
rightSidebarTitle: {
fontWeight: 'bold',
},
labelList: {
@ -75,7 +81,6 @@ function Bug({ bug }: Props) {
<div className={classes.header}>
<BugTitleForm bug={bug} />
</div>
<div className={classes.container}>
<div className={classes.timeline}>
<TimelineQuery id={bug.id} />
@ -87,8 +92,8 @@ function Bug({ bug }: Props) {
)}
</IfLoggedIn>
</div>
<div className={classes.sidebar}>
<span className={classes.sidebarTitle}>Labels</span>
<div className={classes.rightSidebar}>
<span className={classes.rightSidebarTitle}>Labels</span>
<ul className={classes.labelList}>
{bug.labels.length === 0 && (
<span className={classes.noLabel}>None yet</span>

View File

@ -3,6 +3,8 @@ import { RouteComponentProps } from 'react-router-dom';
import CircularProgress from '@material-ui/core/CircularProgress';
import NotFoundPage from '../notfound/NotFoundPage';
import Bug from './Bug';
import { useGetBugQuery } from './BugQuery.generated';
@ -15,8 +17,8 @@ const BugQuery: React.FC<Props> = ({ match }: Props) => {
variables: { id: match.params.id },
});
if (loading) return <CircularProgress />;
if (!data?.repository?.bug) return <NotFoundPage />;
if (error) return <p>Error: {error}</p>;
if (!data?.repository?.bug) return <p>404.</p>;
return <Bug bug={data.repository.bug} />;
};

View File

@ -28,6 +28,7 @@ const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
},
actions: {
display: 'flex',
gap: '1em',
justifyContent: 'flex-end',
},
greenButton: {

View File

@ -40,7 +40,7 @@ function CountingFilter({ query, children, ...props }: CountingFilterProps) {
variables: { query },
});
var prefix;
let prefix;
if (loading) prefix = '...';
else if (error || !data?.repository) prefix = '???';
// TODO: better prefixes & error handling

View File

@ -1,7 +1,7 @@
import React, { FormEvent, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { Button } from '@material-ui/core';
import Paper from '@material-ui/core/Paper';
import { Button, Paper } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import BugTitleInput from '../../components/BugTitleForm/BugTitleInput';
@ -47,7 +47,9 @@ function NewBugPage() {
const [issueTitle, setIssueTitle] = useState('');
const [issueComment, setIssueComment] = useState('');
const classes = useStyles();
let issueTitleInput: any;
let history = useHistory();
function submitNewIssue(e: FormEvent) {
e.preventDefault();
@ -59,12 +61,15 @@ function NewBugPage() {
message: issueComment,
},
},
}).then(function (data) {
const id = data.data?.newBug.bug.humanId;
history.push('/bug/' + id);
});
issueTitleInput.value = '';
}
function isFormValid() {
return issueTitle.length > 0 && issueComment.length > 0 ? true : false;
return issueTitle.length > 0;
}
if (loading) return <div>Loading...</div>;

View File

@ -0,0 +1,52 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import BackToListButton from '../../components/BackToListButton';
const useStyles = makeStyles((theme) => ({
main: {
maxWidth: 1000,
margin: 'auto',
marginTop: theme.spacing(10),
},
logo: {
height: '350px',
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
},
icon: {
display: 'block',
marginLeft: 'auto',
marginRight: 'auto',
fontSize: '80px',
},
backLink: {
marginTop: theme.spacing(1),
textAlign: 'center',
},
header: {
fontSize: '30px',
textAlign: 'center',
},
}));
function NotFoundPage() {
const classes = useStyles();
return (
<main className={classes.main}>
<h1 className={classes.header}>404 Page not found</h1>
<img
src="/logo-alpha-flat-outline.svg"
className={classes.logo}
alt="git-bug Logo"
/>
<div className={classes.backLink}>
<BackToListButton />
</div>
</main>
);
}
export default NotFoundPage;

View File

@ -4,7 +4,8 @@ const defaultDarkTheme = createMuiTheme({
palette: {
type: 'dark',
primary: {
main: '#263238',
dark: '#263238',
main: '#2a393e',
light: '#525252',
},
error: {

View File

@ -4,8 +4,10 @@ const defaultLightTheme = createMuiTheme({
palette: {
type: 'light',
primary: {
main: '#263238',
dark: '#263238',
main: '#5a6b73',
light: '#f5f5f5',
contrastText: '#fff',
},
info: {
main: '#e2f1ff',