diff options
author | Michael Muré <batolettre@gmail.com> | 2021-02-08 09:35:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-08 09:35:45 +0100 |
commit | ef7a0f1b11c8e44a44f1ec23a68cab2adefad36c (patch) | |
tree | e6f345e4968f59c8f521d27f1caebff076a40143 /webui/src/components | |
parent | 0eb4a5907118f5cad6e4dea64a6ca87aad0247ee (diff) | |
parent | 29ea8df4259921f1789e0e6d584767fc5f54b284 (diff) | |
download | git-bug-ef7a0f1b11c8e44a44f1ec23a68cab2adefad36c.tar.gz |
Merge pull request #555 from claudioantonio/master
Commit for #541
Diffstat (limited to 'webui/src/components')
-rw-r--r-- | webui/src/components/Author.tsx | 2 | ||||
-rw-r--r-- | webui/src/components/CommentInput/CommentInput.tsx | 107 | ||||
-rw-r--r-- | webui/src/components/CurrentIdentity/CurrentIdentity.graphql | 8 | ||||
-rw-r--r-- | webui/src/components/CurrentIdentity/CurrentIdentity.tsx | 31 | ||||
-rw-r--r-- | webui/src/components/Header/Header.tsx | 50 | ||||
-rw-r--r-- | webui/src/components/Header/index.tsx | 18 | ||||
-rw-r--r-- | webui/src/components/IfLoggedIn/IfLoggedIn.tsx | 14 | ||||
-rw-r--r-- | webui/src/components/Label.tsx | 3 | ||||
-rw-r--r-- | webui/src/components/fragments.graphql | 19 |
9 files changed, 230 insertions, 22 deletions
diff --git a/webui/src/components/Author.tsx b/webui/src/components/Author.tsx index 9ac1da52..d60e8969 100644 --- a/webui/src/components/Author.tsx +++ b/webui/src/components/Author.tsx @@ -3,7 +3,7 @@ import React from 'react'; import MAvatar from '@material-ui/core/Avatar'; import Tooltip from '@material-ui/core/Tooltip/Tooltip'; -import { AuthoredFragment } from './fragments.generated'; +import { AuthoredFragment } from '../graphql/fragments.generated'; type Props = AuthoredFragment & { className?: string; diff --git a/webui/src/components/CommentInput/CommentInput.tsx b/webui/src/components/CommentInput/CommentInput.tsx new file mode 100644 index 00000000..86cc7dbb --- /dev/null +++ b/webui/src/components/CommentInput/CommentInput.tsx @@ -0,0 +1,107 @@ +import React, { useState, useEffect } from 'react'; + +import Tab from '@material-ui/core/Tab'; +import Tabs from '@material-ui/core/Tabs'; +import TextField from '@material-ui/core/TextField'; +import { makeStyles } from '@material-ui/core/styles'; + +import Content from 'src/components/Content'; + +/** + * Styles + */ +const useStyles = makeStyles((theme) => ({ + container: { + margin: theme.spacing(2, 0), + padding: theme.spacing(0, 2, 2, 2), + }, + textarea: {}, + tabContent: { + margin: theme.spacing(2, 0), + }, + preview: { + borderBottom: `solid 3px ${theme.palette.grey['200']}`, + minHeight: '5rem', + }, +})); + +type TabPanelProps = { + children: React.ReactNode; + value: number; + index: number; +} & React.HTMLProps<HTMLDivElement>; +function TabPanel({ children, value, index, ...props }: TabPanelProps) { + return ( + <div + role="tabpanel" + hidden={value !== index} + id={`editor-tabpanel-${index}`} + aria-labelledby={`editor-tab-${index}`} + {...props} + > + {value === index && children} + </div> + ); +} + +const a11yProps = (index: number) => ({ + id: `editor-tab-${index}`, + 'aria-controls': `editor-tabpanel-${index}`, +}); + +type Props = { + inputProps?: any; + loading: boolean; + onChange: (comment: string) => void; +}; + +/** + * Component for issue comment input + * + * @param inputProps Reset input value + * @param loading Disable input when component not ready yet + * @param onChange Callback to return input value changes + */ +function CommentInput({ inputProps, loading, onChange }: Props) { + const [input, setInput] = useState<string>(''); + const [tab, setTab] = useState(0); + const classes = useStyles(); + + useEffect(() => { + if (inputProps) setInput(inputProps.value); + }, [inputProps]); + + useEffect(() => { + onChange(input); + }, [input, onChange]); + + return ( + <div> + <Tabs value={tab} onChange={(_, t) => setTab(t)}> + <Tab label="Write" {...a11yProps(0)} /> + <Tab label="Preview" {...a11yProps(1)} /> + </Tabs> + <div className={classes.tabContent}> + <TabPanel value={tab} index={0}> + <TextField + fullWidth + label="Comment" + placeholder="Leave a comment" + className={classes.textarea} + multiline + value={input} + variant="filled" + rows="4" // TODO: rowsMin support + onChange={(e: any) => setInput(e.target.value)} + disabled={loading} + /> + </TabPanel> + <TabPanel value={tab} index={1} className={classes.preview}> + <Content markdown={input} /> + </TabPanel> + </div> + </div> + ); +} + +export default CommentInput; diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.graphql b/webui/src/components/CurrentIdentity/CurrentIdentity.graphql new file mode 100644 index 00000000..2794a40f --- /dev/null +++ b/webui/src/components/CurrentIdentity/CurrentIdentity.graphql @@ -0,0 +1,8 @@ +query CurrentIdentity { + repository { + userIdentity { + displayName + avatarUrl + } + } +} diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.tsx b/webui/src/components/CurrentIdentity/CurrentIdentity.tsx new file mode 100644 index 00000000..8cd3585b --- /dev/null +++ b/webui/src/components/CurrentIdentity/CurrentIdentity.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import Avatar from '@material-ui/core/Avatar'; +import { makeStyles } from '@material-ui/core/styles'; + +import { useCurrentIdentityQuery } from './CurrentIdentity.generated'; + +const useStyles = makeStyles((theme) => ({ + displayName: { + marginLeft: theme.spacing(2), + }, +})); + +const CurrentIdentity = () => { + const classes = useStyles(); + const { loading, error, data } = useCurrentIdentityQuery(); + + if (error || loading || !data?.repository?.userIdentity) return null; + + const user = data.repository.userIdentity; + return ( + <> + <Avatar src={user.avatarUrl ? user.avatarUrl : undefined}> + {user.displayName.charAt(0).toUpperCase()} + </Avatar> + <div className={classes.displayName}>{user.displayName}</div> + </> + ); +}; + +export default CurrentIdentity; diff --git a/webui/src/components/Header/Header.tsx b/webui/src/components/Header/Header.tsx new file mode 100644 index 00000000..3e39b5f3 --- /dev/null +++ b/webui/src/components/Header/Header.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; + +import AppBar from '@material-ui/core/AppBar'; +import Toolbar from '@material-ui/core/Toolbar'; +import { makeStyles } from '@material-ui/core/styles'; + +import CurrentIdentity from '../CurrentIdentity/CurrentIdentity'; + +const useStyles = makeStyles((theme) => ({ + offset: { + ...theme.mixins.toolbar, + }, + filler: { + flexGrow: 1, + }, + appTitle: { + ...theme.typography.h6, + color: 'white', + textDecoration: 'none', + display: 'flex', + alignItems: 'center', + }, + logo: { + height: '42px', + marginRight: theme.spacing(2), + }, +})); + +function Header() { + const classes = useStyles(); + + return ( + <> + <AppBar position="fixed" color="primary"> + <Toolbar> + <Link to="/" className={classes.appTitle}> + <img src="/logo.svg" className={classes.logo} alt="git-bug" /> + git-bug + </Link> + <div className={classes.filler}></div> + <CurrentIdentity /> + </Toolbar> + </AppBar> + <div className={classes.offset} /> + </> + ); +} + +export default Header; diff --git a/webui/src/components/Header/index.tsx b/webui/src/components/Header/index.tsx new file mode 100644 index 00000000..42a0cfc1 --- /dev/null +++ b/webui/src/components/Header/index.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import CssBaseline from '@material-ui/core/CssBaseline'; + +import Header from './Header'; + +type Props = { children: React.ReactNode }; +function Layout({ children }: Props) { + return ( + <> + <CssBaseline /> + <Header /> + {children} + </> + ); +} + +export default Layout; diff --git a/webui/src/components/IfLoggedIn/IfLoggedIn.tsx b/webui/src/components/IfLoggedIn/IfLoggedIn.tsx new file mode 100644 index 00000000..2476aad8 --- /dev/null +++ b/webui/src/components/IfLoggedIn/IfLoggedIn.tsx @@ -0,0 +1,14 @@ +import React from 'react'; + +import { useCurrentIdentityQuery } from '../CurrentIdentity/CurrentIdentity.generated'; + +type Props = { children: () => React.ReactNode }; +const IfLoggedIn = ({ children }: Props) => { + const { loading, error, data } = useCurrentIdentityQuery(); + + if (error || loading || !data?.repository?.userIdentity) return null; + + return <>{children()}</>; +}; + +export default IfLoggedIn; diff --git a/webui/src/components/Label.tsx b/webui/src/components/Label.tsx index 4aaa6bb6..111f6d7f 100644 --- a/webui/src/components/Label.tsx +++ b/webui/src/components/Label.tsx @@ -7,10 +7,9 @@ import { darken, } from '@material-ui/core/styles/colorManipulator'; +import { LabelFragment } from '../graphql/fragments.generated'; import { Color } from 'src/gqlTypes'; -import { LabelFragment } from './fragments.generated'; - // Minimum contrast between the background and the text color const contrastThreshold = 2.5; diff --git a/webui/src/components/fragments.graphql b/webui/src/components/fragments.graphql deleted file mode 100644 index 03a235f9..00000000 --- a/webui/src/components/fragments.graphql +++ /dev/null @@ -1,19 +0,0 @@ -# Label.tsx -fragment Label on Label { - name - color { - R - G - B - } -} - -# Author.tsx -fragment authored on Authored { - author { - name - email - displayName - avatarUrl - } -} |