feat: add identity and feed management (#272)

* feat(wip): add basic feed operations

* ci: bump checks

* ci: bump checks

* feat: rework stamps and add feed functionalities

* refactor: polish and fixes

* feat(wip): add formulas

* feat: show bzz.link for websites

* feat: add stamp empty states and formatBzz

* feat: add feed download

* chore: update manifest-js version

* feat: dev mode support with bee-js 3.1.0 (#273)

* feat: dev mode support with bee-js 3.1.0

* fix: added missing package-lock.json file

* build: remove PR preview

* style: work on design

* feat: add TroubleshootConnectionCard

* build: remove depcheck

Co-authored-by: Attila Gazso <agazso@gmail.com>
This commit is contained in:
Cafe137
2021-12-21 10:58:54 +01:00
committed by GitHub
parent d7c59a1495
commit 25b65c3fb7
46 changed files with 4354 additions and 6378 deletions
+26
View File
@@ -0,0 +1,26 @@
import { createStyles, makeStyles, Theme } from '@material-ui/core'
import { Close } from '@material-ui/icons'
import { ReactElement } from 'react'
interface Props {
onClose: () => void
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
wrapper: {
padding: theme.spacing(1),
cursor: 'pointer',
},
}),
)
export function CloseButton({ onClose }: Props): ReactElement {
const classes = useStyles()
return (
<div className={classes.wrapper} onClick={onClose}>
<Close />
</div>
)
}
+38
View File
@@ -0,0 +1,38 @@
import { createStyles, makeStyles, Theme } from '@material-ui/core'
import { ReactElement } from 'react'
interface Props {
children: string
prettify?: boolean
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
wrapper: {
overflow: 'scroll',
background: '#ffffff',
},
pre: {
maxHeight: '6em',
padding: theme.spacing(2),
},
}),
)
function prettifyString(string: string): string {
try {
return JSON.stringify(JSON.parse(string), null, 4)
} catch {
return string
}
}
export function Code({ children, prettify }: Props): ReactElement {
const classes = useStyles()
return (
<div className={classes.wrapper}>
<pre className={classes.pre}>{prettify ? prettifyString(children) : children}</pre>
</div>
)
}
+21
View File
@@ -0,0 +1,21 @@
import { createStyles, makeStyles, Typography } from '@material-ui/core'
import { ReactElement } from 'react'
interface Props {
children: (string | ReactElement)[] | (string | ReactElement)
}
const useStyles = makeStyles(() =>
createStyles({
text: {
color: '#606060',
fontSize: '0.9rem',
},
}),
)
export function DocumentationText({ children }: Props): ReactElement {
const classes = useStyles()
return <Typography className={classes.text}>{children}</Typography>
}
+9 -5
View File
@@ -4,8 +4,12 @@ import { ReactElement, ReactNode } from 'react'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
wrapper: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
},
action: {
marginTop: theme.spacing(0.75),
marginBottom: theme.spacing(1),
marginRight: theme.spacing(1),
},
@@ -21,16 +25,16 @@ export default function ExpandableListItemActions({ children }: Props): ReactEle
if (Array.isArray(children)) {
return (
<Grid container direction="row">
<div className={classes.wrapper}>
{children
// Exclude falsy values to allow conditional rendering
.filter(x => x)
.map((a, i) => (
<Grid key={i} className={classes.action}>
<div key={i} className={classes.action}>
{a}
</Grid>
</div>
))}
</Grid>
</div>
)
}
+15 -11
View File
@@ -1,10 +1,11 @@
import { Button, Grid, IconButton, InputBase, ListItem, Typography } from '@material-ui/core'
import { Grid, IconButton, InputBase, ListItem, Typography } from '@material-ui/core'
import Collapse from '@material-ui/core/Collapse'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import { ChangeEvent, ReactElement, useState } from 'react'
import { Check, Edit, Minus, RotateCcw } from 'react-feather'
import { Edit, Minus, Search, X } from 'react-feather'
import ExpandableListItemActions from './ExpandableListItemActions'
import ExpandableListItemNote from './ExpandableListItemNote'
import { SwarmButton } from './SwarmButton'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -52,6 +53,7 @@ interface Props {
expandedOnly?: boolean
confirmLabel?: string
confirmLabelDisabled?: boolean
loading?: boolean
onChange?: (value: string) => void
onConfirm: (value: string) => void
mapperFn?: (value: string) => string
@@ -68,6 +70,7 @@ export default function ExpandableListItemKey({
expandedOnly,
helperText,
placeholder,
loading,
mapperFn,
locked,
}: Props): ReactElement | null {
@@ -126,26 +129,27 @@ export default function ExpandableListItemKey({
<Collapse in={open} timeout="auto" unmountOnExit>
{helperText && <ExpandableListItemNote>{helperText}</ExpandableListItemNote>}
<ExpandableListItemActions>
<Button
variant="contained"
<SwarmButton
disabled={
loading ||
inputValue === value ||
Boolean(confirmLabelDisabled) || // Disable if external validation is provided
(inputValue === '' && value === undefined) // Disable if no initial value was not provided and the field is empty. The undefined check is improtant so that it is possible to submit with empty input in other cases
}
startIcon={<Check size="1rem" />}
loading={loading}
iconType={Search}
onClick={() => onConfirm(inputValue)}
>
{confirmLabel || 'Save'}
</Button>
<Button
variant="contained"
disabled={inputValue === value || inputValue === ''}
startIcon={<RotateCcw size="1rem" />}
</SwarmButton>
<SwarmButton
disabled={loading || inputValue === value || inputValue === ''}
iconType={X}
onClick={() => setInputValue(value || '')}
cancel
>
Cancel
</Button>
</SwarmButton>
</ExpandableListItemActions>
</Collapse>
</>
+55
View File
@@ -0,0 +1,55 @@
import { createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
import { ReactElement } from 'react'
interface Props {
steps: string[]
index: number
}
const useStyles = makeStyles(() =>
createStyles({
wrapper: {
height: '52px',
display: 'flex',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
todo: {
background: '#f7f7f7',
color: '#c9c9c9',
},
inProgress: {
background: '#ffffff',
color: '#242424',
height: '52px',
},
done: {
background: '#f7f7f7',
color: '#606060',
height: '52px',
},
}),
)
export function ProgressIndicator({ steps, index }: Props): ReactElement {
const classes = useStyles()
function pickClass(i: number): string {
if (i === index) {
return classes.inProgress
}
return i < index ? classes.done : classes.todo
}
return (
<Grid container justifyContent="space-between">
{steps.map((x, i) => (
<div key={i} className={`${classes.wrapper} ${pickClass(i)}`}>
<Typography>{x}</Typography>
</div>
))}
</Grid>
)
}
+6 -1
View File
@@ -2,7 +2,7 @@ import { Divider, Drawer, Grid, Link as MUILink, List } from '@material-ui/core'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import { OpenInNewSharp } from '@material-ui/icons'
import type { ReactElement } from 'react'
import { BookOpen, DollarSign, FileText, Home, Layers, Settings } from 'react-feather'
import { Bookmark, BookOpen, DollarSign, FileText, Home, Layers, Settings } from 'react-feather'
import { Link } from 'react-router-dom'
import Logo from '../assets/logo.svg'
import { config } from '../config'
@@ -21,6 +21,11 @@ const navBarItems = [
path: ROUTES.UPLOAD,
icon: FileText,
},
{
label: 'Feeds',
path: ROUTES.FEEDS,
icon: Bookmark,
},
{
label: 'Stamps',
path: ROUTES.STAMPS,
+30 -5
View File
@@ -9,13 +9,16 @@ interface Props {
className?: string
disabled?: boolean
loading?: boolean
cancel?: boolean
}
const useStyles = makeStyles(() =>
createStyles({
button: {
height: '52px',
position: 'relative',
whiteSpace: 'nowrap',
color: '#242424',
'&:hover, &:focus': {
'& svg': {
stroke: '#fff',
@@ -23,6 +26,10 @@ const useStyles = makeStyles(() =>
},
},
},
cancelButton: {
background: '#f7f7f7',
color: '#606060',
},
spinnerWrapper: {
position: 'absolute',
left: '50%',
@@ -34,19 +41,37 @@ const useStyles = makeStyles(() =>
}),
)
export function SwarmButton({ children, onClick, iconType, className, disabled, loading }: Props): ReactElement {
export function SwarmButton({
children,
onClick,
iconType,
className,
disabled,
loading,
cancel,
}: Props): ReactElement {
const classes = useStyles()
function getIconColor() {
if (loading || disabled) {
return 'rgba(0, 0, 0, 0.26)'
}
return cancel ? '#606060' : '#dd7700'
}
function getButtonClassName() {
return [className, classes.button, cancel && classes.cancelButton].filter(x => x).join(' ')
}
const icon = React.createElement(iconType, {
size: '1.25rem',
color: disabled ? 'rgba(0, 0, 0, 0.26)' : '#dd7700',
color: getIconColor(),
})
const classNames = className ? [className, classes.button].join(' ') : classes.button
return (
<Button
className={classNames}
className={getButtonClassName()}
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
onClick()
event.currentTarget.blur()
+23
View File
@@ -0,0 +1,23 @@
import { Box, Dialog, Grid } from '@material-ui/core'
import { ReactElement } from 'react'
interface Props {
children: ReactElement | ReactElement[]
}
export function SwarmDialog({ children }: Props): ReactElement {
return (
<Dialog
open={true}
PaperProps={{
style: { borderRadius: 0, background: '#efefef' },
}}
>
<Box p={4} sx={{ maxWidth: '100%', width: '650px' }}>
<Grid container direction="column">
{children}
</Grid>
</Box>
</Dialog>
)
}
+83
View File
@@ -0,0 +1,83 @@
import { createStyles, FormHelperText, makeStyles, MenuItem, Select as SimpleSelect, Theme } from '@material-ui/core'
import { Field } from 'formik'
import { Select } from 'formik-material-ui'
import { ReactElement } from 'react'
export type SelectEvent = React.ChangeEvent<{
name?: string | undefined
value: unknown
}>
interface Props {
label?: string
name?: string
options: { value: string; label: string }[]
onChange?: (event: SelectEvent) => void
formik?: boolean
defaultValue?: string
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
select: {
borderRadius: 0,
background: theme.palette.background.paper,
'& fieldset': {
border: 0,
},
},
option: {
height: '52px',
},
}),
)
export function SwarmSelect({ defaultValue, formik, name, options, onChange, label }: Props): ReactElement {
const classes = useStyles()
if (formik) {
return (
<>
{label && <FormHelperText>{label}</FormHelperText>}
<Field
required
component={Select}
name={name}
fullWidth
variant="outlined"
defaultValue={defaultValue || ''}
className={classes.select}
placeholder={label}
>
{options.map((x, i) => (
<MenuItem key={i} value={x.value} className={classes.option}>
{x.label}
</MenuItem>
))}
</Field>
</>
)
}
return (
<>
{label && <FormHelperText>{label}</FormHelperText>}
<SimpleSelect
required
name={name}
fullWidth
variant="outlined"
className={classes.select}
defaultValue={defaultValue || ''}
onChange={onChange}
placeholder={label}
>
{options.map((x, i) => (
<MenuItem key={i} value={x.value} className={classes.option}>
{x.label}
</MenuItem>
))}
</SimpleSelect>
</>
)
}
+58
View File
@@ -0,0 +1,58 @@
import { createStyles, makeStyles, TextField as SimpleTextField, Theme } from '@material-ui/core'
import { Field } from 'formik'
import { TextField } from 'formik-material-ui'
import { ChangeEvent, ReactElement } from 'react'
interface Props {
name: string
label: string
password?: boolean
formik?: boolean
optional?: boolean
onChange?: (event: ChangeEvent<HTMLTextAreaElement>) => void
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
field: {
background: theme.palette.background.paper,
height: '52px',
'& fieldset': {
border: 0,
},
},
}),
)
export function SwarmTextInput({ name, label, password, optional, formik, onChange }: Props): ReactElement {
const classes = useStyles()
if (formik) {
return (
<Field
component={TextField}
type={password ? 'password' : undefined}
required={!optional}
name={name}
label={label}
fullWidth
variant="outlined"
className={classes.field}
defaultValue=""
/>
)
}
return (
<SimpleTextField
type={password ? 'password' : undefined}
required
label={label}
fullWidth
variant="outlined"
className={classes.field}
defaultValue=""
onChange={onChange}
/>
)
}
+31
View File
@@ -0,0 +1,31 @@
import { createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
import { ReactElement } from 'react'
import { CloseButton } from './CloseButton'
interface Props {
children: string
onClose: () => void
}
const useStyles = makeStyles(() =>
createStyles({
text: {
color: '#606060',
fontWeight: 'bold',
},
}),
)
export function TitleWithClose({ children, onClose }: Props): ReactElement {
const classes = useStyles()
return (
<Grid container justifyContent="space-between" alignItems="center">
<span>&nbsp;</span>
<Typography className={classes.text} align="center">
{children}
</Typography>
<CloseButton onClose={onClose} />
</Grid>
)
}