theme-ui#Heading TypeScript Examples
The following examples show how to use
theme-ui#Heading.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Error.tsx From nft-market with MIT License | 6 votes |
Error = () => {
return (
<Flex>
<Image sx={{ width: 100, height: 100 }} src="/icons/icon-512x512.png" />
<Box mt={4} ml={4}>
<Heading as="h2">Metamask not installed</Heading>
<Text mt={2}>
Go to{' '}
<Link href="https://metamask.io" target="_blank">
https://metamask.io
</Link>{' '}
to install it.
</Text>
</Box>
</Flex>
)
}
Example #2
Source File: Logo.tsx From slice-machine with Apache License 2.0 | 6 votes |
Logo: React.FC = () => {
const { theme } = useThemeUI();
return (
<Box p={2}>
<Link href="/" passHref>
<ThemeLink variant="links.invisible">
<Flex sx={{ alignItems: "center" }}>
<SliceMachineLogo
width="32px"
height="32px"
fill={theme.colors?.text as string}
/>
<Heading as="h5" sx={{ ml: 2 }}>
Slice Machine
</Heading>
</Flex>
</ThemeLink>
</Link>
</Box>
);
}
Example #3
Source File: UserMenu.tsx From nft-market with MIT License | 6 votes |
UserMenu = () => {
const { user, isAuthenticated } = useAppState()
const history = useHistory()
return (
<Flex sx={{ ml: 'auto', justifySelf: 'flex-end' }}>
{isAuthenticated && user && (
<>
<Box sx={{ display: ['none', 'block'] }}>
<Heading sx={{ p: 0, color: 'white' }} as="h4">
{toShort(user.address)}
</Heading>
<Heading sx={{ p: 0, mt: 1, textAlign: 'right', color: 'white' }} as="h5">
{EtherSymbol}
{user.balance}
</Heading>
</Box>
<Box
onClick={() => {
history.push('/profile')
}}
sx={{
cursor: 'pointer',
ml: [0, 3],
height: 30,
width: 30,
borderRadius: '100%',
}}
>
<Identicon size={30} address={user.address} />
</Box>
</>
)}
</Flex>
)
}
Example #4
Source File: ContractDetails.tsx From nft-market with MIT License | 6 votes |
ContractDetails = () => {
const { contractDetails } = useAppState()
return (
<Box>
<Heading as="h1">NFT Contract Details</Heading>
<Grid my={3}>
{contractDetails &&
Object.keys(contractDetails).map(a => (
<Text key={a}>
{a}:{' '}
<Text variant="text.bold" as="span">
{contractDetails[a as keyof ContractPropsDetails]}
</Text>
</Text>
))}
</Grid>
</Box>
)
}
Example #5
Source File: onboarding.tsx From slice-machine with Apache License 2.0 | 6 votes |
Header = (props: HeadingProps) => (
<Heading
{...props}
sx={{
textAlign: "center",
...props.sx,
}}
style={{
fontSize: "20px",
lineHeight: "1.5",
fontWeight: 700,
}}
/>
)
Example #6
Source File: index.tsx From slice-machine with Apache License 2.0 | 6 votes |
ZoneEmptyState = ({
onEnterSelectMode,
zoneName,
}: {
// eslint-disable-next-line @typescript-eslint/ban-types
onEnterSelectMode: Function;
zoneName: string;
}) => (
<Box sx={{ textAlign: "center", my: 4 }}>
<Heading as="h5">Add a new field here</Heading>
<Box sx={{ my: 2 }}>
<Text sx={{ color: "textClear" }}>
Add a field to your {zoneName} Zone
</Text>
</Box>
<Button
mt={3}
variant="buttons.darkSmall"
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
onClick={() => onEnterSelectMode()}
data-testid="empty-zone-add-new-field"
>
<FaPlus
style={{ marginRight: "8px", position: "relative", top: "2px" }}
/>{" "}
Add a new field
</Button>
</Box>
)
Example #7
Source File: index.tsx From slice-machine with Apache License 2.0 | 5 votes |
SharedSlice = {
render({
bordered,
slice,
displayStatus,
Wrapper,
CustomStatus,
thumbnailHeightPx = "280px",
wrapperType = WrapperType.clickable,
sx,
}: {
bordered?: boolean;
displayStatus?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
CustomStatus?: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Wrapper?: any /* ? */;
slice: SliceState;
wrapperType?: WrapperType;
thumbnailHeightPx?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sx?: any;
}) {
const defaultVariation = SliceState.variation(slice);
if (!defaultVariation) {
return null;
}
const variationId = defaultVariation.id;
const link = LinkUtil.variation(slice.href, slice.model.name, variationId);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const CardWrapper = Wrapper || WrapperByType[wrapperType];
const screenshotUrl = slice?.screenshotUrls?.[variationId]?.url;
return (
<CardWrapper link={link} slice={slice}>
<Themecard
role="button"
aria-pressed="false"
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-argument
sx={bordered ? borderedSx(sx) : defaultSx(sx)}
>
<SliceThumbnail
withShadow={false}
screenshotUrl={screenshotUrl}
heightInPx={thumbnailHeightPx}
/>
<Flex
mt={3}
sx={{ alignItems: "center", justifyContent: "space-between" }}
>
<Flex sx={{ alignItems: "center" }}>
{CustomStatus ? (
<CustomStatus slice={slice} />
) : (
<Fragment>
{displayStatus && slice.__status ? (
<StatusBadge libStatus={slice.__status} />
) : null}
</Fragment>
)}
<Heading sx={{ flex: 1 }} as="h6">
{slice.model.name}
</Heading>
</Flex>
<SliceVariations
variations={slice.variations}
hideVariations={false}
/>
</Flex>
</Themecard>
</CardWrapper>
);
},
}
Example #8
Source File: Profile.tsx From nft-market with MIT License | 5 votes |
Profile = () => {
const { user, tokensOnSale } = useAppState()
if (!user) return null
const { address, balance, ownedTokens } = user
return (
<Box>
<Heading as="h1">My Profile</Heading>
<Grid columns={['1fr', '1fr 1fr']} sx={{ overflow: 'hidden', gap: '0 20px' }}>
<Box>
<Heading as="h4" sx={{ color: 'green' }}>
Address
</Heading>
<Text>{address}</Text>
</Box>
<Box>
<Heading as="h4" sx={{ color: 'green' }}>
Balance
</Heading>
<Text>Ξ {balance}</Text>
</Box>
</Grid>
<Divider variant="divider.nft" sx={{ my: 7 }} />
<Box my={5}>
{ownedTokens && ownedTokens.length > 0 ? (
<Box>
<Heading as="h2">
My items{' '}
<Text variant="text.body" as="span">
({ownedTokens.length} item)
</Text>
</Heading>
<Grid gap={4} columns={['1fr 1fr', '1fr 1fr 1fr']}>
{ownedTokens.map((t, index) => (
<Token
isOnSale={
!!tokensOnSale?.find(a => utils.formatUnits(a.id) === utils.formatUnits(t.id))
}
onSale
onTransfer
token={t}
key={index}
/>
))}
</Grid>
</Box>
) : (
ownedTokens && (
<Box>
<Heading as="h2">You don't own any NFT tokens</Heading>
</Box>
)
)}
</Box>
</Box>
)
}
Example #9
Source File: Connect.tsx From nft-market with MIT License | 5 votes |
Connect: FC = ({ children }) => {
const { activatingConnector } = useAppState()
const { library, chainId, account, error } = useWeb3React()
const { setContract, setUser } = useAppState(
useCallback(
({ setContract, setUser }) => ({
setContract,
setUser,
}),
[]
)
)
useSWR(ETHSCAN_API, fetcherETHUSD)
useEffect(() => {
if (!chainId || !account || !library) return
const update = async () => {
try {
await setContract(library, chainId)
setUser(account)
} catch (e) {
console.log(e)
}
}
update()
}, [chainId, account, library, setContract, setUser])
const triedEager = useEagerConnect()
useInactiveListener(!triedEager || !!activatingConnector)
return (
<>
{error ? (
<Container>
<Heading as="h2">❌ Something is not right</Heading>
<Text sx={{ mt: 3 }}>{getErrorMessage(error)}</Text>
</Container>
) : (
children
)}
</>
)
}
Example #10
Source File: Header.tsx From nft-market with MIT License | 5 votes |
Header = () => {
const history = useHistory()
const location = useLocation()
const { user, isAuthenticated } = useAppState()
return (
<Box bg="black">
<Flex sx={{ alignItems: 'center', p: 3 }} as="nav">
<Image
onClick={() => {
history.push('/')
}}
sx={{ width: 50, cursor: 'pointer' }}
src="/static/logo.png"
/>
<Heading sx={{ ml: [1, 2], color: 'white' }} as="h4">
ERC721 Marketplace{' '}
<Text sx={{ display: ['none', 'block'] }}>+ OpenSea.io on Rinkeby Network</Text>
</Heading>
<UserMenu />
</Flex>
{isAuthenticated && user && (
<Flex bg="midGray" py={3} sx={{ justifyContent: 'center' }}>
<NavLink
sx={{
pointerEvents: location.pathname === '/' ? 'none' : 'visible',
color: location.pathname === '/' ? 'green' : 'white',
}}
onClick={() => history.push('/')}
>
Marketplace
</NavLink>
<Box sx={{ width: 50 }} />
<NavLink
sx={{
pointerEvents: location.pathname === '/profile' ? 'none' : 'visible',
color: location.pathname === '/profile' ? 'green' : 'white',
}}
onClick={() => history.push('/profile')}
>
Profile
</NavLink>
</Flex>
)}
</Box>
)
}
Example #11
Source File: Gallery.tsx From nft-market with MIT License | 5 votes |
Gallery = () => {
const { user, tokensOnSale } = useAppState()
const updateTokensOnSale = useAppState(
useCallback(({ updateTokensOnSale }) => updateTokensOnSale, [])
)
const [order, setOrder] = useState<StateOrder>('alpha')
useEffect(() => {
updateTokensOnSale()
}, [updateTokensOnSale])
return (
<Box>
<Heading as="h1">Marketplace</Heading>
<Flex sx={{ alignItems: 'center' }} mb={3}>
<Heading as="h3" sx={{ color: 'lightGray' }}>
Order:
</Heading>
<Flex ml={3}>
<Button
mr={2}
onClick={() => setOrder('alpha')}
variant="filter"
disabled={order === 'alpha'}
>
Alphabetically
</Button>
<Button onClick={() => setOrder('price')} variant="filter" disabled={order === 'price'}>
Price
</Button>
</Flex>
</Flex>
<Grid gap={4} columns={['1fr 1fr', '1fr 1fr', '1fr 1fr 1fr']}>
{tokensOnSale
?.sort((a, b) =>
order === 'alpha'
? BigNumber.from(a.id)
.toString()
.localeCompare(BigNumber.from(b.id).toString(), undefined, { numeric: true })
: Number(utils.formatEther(a.price.sub(b.price)))
)
.map((i, index) => (
<Token onBuy={!user?.ownedTokens.find(t => t.id === i.id)} token={i} key={index} />
))}
</Grid>
</Box>
)
}
Example #12
Source File: index.tsx From slice-machine with Apache License 2.0 | 5 votes |
NonSharedSlice = {
render({
bordered,
slice,
displayStatus,
thumbnailHeightPx = "280px",
wrapperType = WrapperType.nonClickable,
sx,
}: {
bordered: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
slice: { key: string; value: any };
displayStatus?: boolean;
thumbnailHeightPx?: string;
wrapperType?: WrapperType;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sx?: any;
}) {
const Wrapper = WrapperByType[wrapperType];
return (
<Wrapper link={undefined}>
{/* eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-argument */}
<Themecard sx={bordered ? borderedSx(sx) : defaultSx(sx)}>
<SliceThumbnail withShadow={false} heightInPx={thumbnailHeightPx} />
<Flex
mt={3}
sx={{ alignItems: "center", justifyContent: "space-between" }}
>
<Flex>
{displayStatus ? (
<Badge mr={2} variant="modified">
Non shared
</Badge>
) : null}
<Heading sx={{ flex: 1 }} as="h6">
{/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */}
{slice?.value?.fieldset || slice.key}
</Heading>
</Flex>
</Flex>
</Themecard>
</Wrapper>
);
},
}
Example #13
Source File: index.tsx From slice-machine with Apache License 2.0 | 5 votes |
SliceZone: React.FC<SliceZoneProps> = ({
tabId,
sliceZone,
onSelectSharedSlices,
onRemoveSharedSlice,
onCreateSliceZone,
}) => {
const [formIsOpen, setFormIsOpen] = useState(false);
const libraries = useContext(LibrariesContext);
const { availableSlices, slicesInSliceZone, notFound } = sliceZone
? mapAvailableAndSharedSlices(sliceZone, libraries)
: { availableSlices: [], slicesInSliceZone: [], notFound: [] };
useEffect(() => {
if (notFound?.length) {
notFound.forEach(({ key }) => {
onRemoveSharedSlice(key);
});
}
}, [notFound]);
const sharedSlicesInSliceZone = slicesInSliceZone
.filter((e) => e.type === SlicesTypes.SharedSlice)
.map((e) => e.payload) as ReadonlyArray<SliceState>;
/* Preserve these keys in SliceZone */
const nonSharedSlicesKeysInSliceZone = slicesInSliceZone
.filter((e) => e.type === SlicesTypes.Slice)
.map((e) => (e.payload as NonSharedSliceInSliceZone).key);
const onAddNewSlice = () => {
if (!sliceZone) {
onCreateSliceZone();
}
setFormIsOpen(true);
};
return (
<Box my={3}>
<ZoneHeader
Heading={<Heading as="h6">Slice Zone</Heading>}
Actions={
<Flex sx={{ alignItems: "center" }}>
{sliceZone ? (
<Text pr={3} sx={{ fontSize: "14px" }}>
data.{sliceZone.key}
</Text>
) : null}
{!!slicesInSliceZone.length && (
<Button variant="buttons.darkSmall" onClick={onAddNewSlice}>
Update Slice Zone
</Button>
)}
</Flex>
}
/>
{!slicesInSliceZone.length ? (
<EmptyState onAddNewSlice={onAddNewSlice} />
) : (
<SlicesList slices={slicesInSliceZone} />
)}
<UpdateSliceZoneModal
isOpen={formIsOpen}
formId={`tab-slicezone-form-${tabId}`}
availableSlices={availableSlices}
slicesInSliceZone={sharedSlicesInSliceZone}
onSubmit={({ sliceKeys }) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
onSelectSharedSlices(sliceKeys, nonSharedSlicesKeysInSliceZone)
}
close={() => setFormIsOpen(false)}
/>
</Box>
);
}
Example #14
Source File: index.tsx From slice-machine with Apache License 2.0 | 5 votes |
EmptyState: React.FunctionComponent<Props> = ({ title, onCreateNew, buttonText, isLoading, documentationComponent, }) => ( <Flex sx={(theme) => ({ maxWidth: "480px", flexDirection: "column", border: `1px solid ${theme.colors?.grey02 as string}`, })} > <Flex sx={(theme) => ({ flexDirection: "column", p: 4, borderBottom: `1px solid ${theme.colors?.grey02 as string}`, })} > <Heading as={"h3"} variant={"heading"} sx={{ fontSize: "16px", lineHeight: "24px", mb: 2 }} > {title} </Heading> <Text variant="xs" sx={{ lineHeight: "24px", fontSize: "13px" }}> {documentationComponent} </Text> </Flex> <Flex sx={{ p: 4, alignItems: "center", }} > <Button onClick={onCreateNew} sx={{ display: "flex", justifyContent: "center", alignItems: "center", mr: 4, }} > {isLoading ? <Spinner color="#FFF" size={14} /> : buttonText} </Button> <Text sx={{ fontSize: "12px", color: "grey04", maxWidth: "280px", }} > It will be stored locally and you will be able to push it to your repository </Text> </Flex> </Flex> )
Example #15
Source File: Desktop.tsx From slice-machine with Apache License 2.0 | 5 votes |
UpdateInfo: React.FC<{
onClick: () => void;
hasSeenUpdate: boolean;
}> = ({ onClick, hasSeenUpdate }) => {
return (
<Flex
sx={{
maxWidth: "240px",
border: "1px solid #E6E6EA",
borderRadius: "4px",
padding: "8px",
flexDirection: "column",
}}
>
<Heading
as="h6"
sx={{
fontSize: "14px",
margin: "4px 8px",
}}
>
Updates Available{" "}
{hasSeenUpdate || (
<span
data-testid="the-red-dot"
style={{
borderRadius: "50%",
width: "8px",
height: "8px",
backgroundColor: "#FF4A4A",
display: "inline-block",
margin: "4px",
}}
/>
)}
</Heading>
<Paragraph
sx={{
fontSize: "14px",
color: "#4E4E55",
margin: "4px 8px 8px",
}}
>
Some updates of Slice Machine are available.
</Paragraph>
<Button
data-testid="update-modal-open"
sx={{
background: "#5B3DF5",
border: "1px solid rgba(62, 62, 72, 0.15)",
boxSizing: "border-box",
borderRadius: "4px",
margin: "8px",
fontSize: "11.67px",
alignSelf: "flex-start",
padding: "4px 8px",
}}
onClick={onClick}
>
Learn more
</Button>
</Flex>
);
}
Example #16
Source File: ModalMapSelect.tsx From HappyIslandDesigner with MIT License | 4 votes |
function IslandLayoutSelector() {
const [layoutType, setLayoutType] = useState<LayoutType>(LayoutType.none);
const [layout, setLayout] = useState<number>(-1);
const [help, setHelp] = useState<boolean>(false);
useEffect(() => {
if (layout != -1)
{
const layoutData = getLayouts(layoutType)[layout];
loadMapFromJSONString(layoutData.data);
CloseMapSelectModal();
}
}, [layoutType, layout]);
function getLayouts(type: LayoutType) {
switch (type) {
case LayoutType.west:
return Layouts.west;
case LayoutType.south:
return Layouts.south;
case LayoutType.east:
return Layouts.east;
case LayoutType.blank:
return Layouts.blank;
}
return [];
}
if (help) {
return (
<Flex p={[0, 3]} sx={{flexDirection: 'column', alignItems: 'center', position: 'relative'}}>
<Box sx={{position: 'absolute', left: 0, top: [1, 30]}}>
<Button variant='icon' onClick={() => setHelp(false)}>
<Image sx={{width: 'auto'}} src='static/img/back.png' />
</Button>
</Box>
<Image sx={{width: 100, margin: 'auto'}} src={'static/img/blathers.png'}/>
<Heading m={3} sx={{px: layoutType ? 4 : 0, textAlign: 'center'}}>{'Please help contribute!'}</Heading>
<Text my={2}>{'Sorry, we don\'t have all the map templates yet (there are almost 100 river layouts in the game!). Each option you see here has been hand-made by a member of the community.'}</Text>
<Text my={2}>{'You can use the \'Upload Screenshot\' tool to trace an image of your island. When you\'re done please consider contributing your island map in either the '}<Link href={'https://github.com/eugeneration/HappyIslandDesigner/issues/59'}>Github</Link>{' or '}<Link href={'https://discord.gg/EtaqD5H'}>Discord</Link>!</Text>
<Text my={2}>{'Please note that your island may have different shaped rock formations, beaches, and building positions than another island with the same river layout.'}</Text>
</Flex>
)
}
let content;
if (layoutType != LayoutType.none) {
var layouts: Array<Layout> = getLayouts(layoutType);
content = (
<Grid
gap={0}
columns={[2, 3, 4]}
sx={{justifyItems: 'center' }}>
{
layouts.map((layout, index) => (
<Card
key={index}
onClick={() => {
confirmDestructiveAction(
'Clear your map? You will lose all unsaved changes.',
() => {
setLayout(index);
});
}}>
<Image variant='card' src={`static/img/layouts/${layoutType}-${layout.name}.png`}/>
</Card>
)).concat(
<Card key={'help'} onClick={()=>{setHelp(true)}}>
<Image sx={{width: 24}} src={'static/img/menu-help.png'} />
<Text sx={{fontFamily: 'body'}}>{'Why isn\'t my map here?'}</Text>
</Card>
)
}
</Grid>
);
}
else {
content = (
<Flex sx={{flexDirection: ['column', 'row'], alignItems: 'center'}}>
<Card onClick={() => setLayoutType(LayoutType.west)}><Image variant='card' src={'static/img/island-type-west.png'}/></Card>
<Card onClick={() => setLayoutType(LayoutType.south)}><Image variant='card' src={'static/img/island-type-south.png'}/></Card>
<Card onClick={() => setLayoutType(LayoutType.east)}><Image variant='card' src={'static/img/island-type-east.png'}/></Card>
<Card onClick={() => {
setLayoutType(LayoutType.blank);
confirmDestructiveAction(
'Clear your map? You will lose all unsaved changes.',
() => {
setLayout(0);
});
}}><Image variant='card' src={'static/img/island-type-blank.png'}/></Card> </Flex>
);
}
return (
<Box p={[0, 3]} sx={{position: 'relative'}}>
{layoutType && <Box sx={{position: 'absolute', top: [1, 3]}}>
<Button variant='icon' onClick={() => setLayoutType(LayoutType.none)}>
<Image src='static/img/back.png' />
</Button>
</Box>}
<Heading m={2} sx={{px: layoutType ? 4 : 0, textAlign: 'center'}}>{layoutType ? 'Choose your Island!' : 'Choose your Layout!'}</Heading>
{layoutType && <Text m={2} sx={{textAlign: 'center'}}>{'You probably won\'t find an exact match, but pick one that roughly resembles your island.'}</Text>}
{content}
</Box>
);
}
Example #17
Source File: update.tsx From slice-machine with Apache License 2.0 | 4 votes |
CreateCustomtypeForm = ({
title,
isOpen,
onSubmit,
close,
tabIds,
allowDelete,
}: {
title: string;
isOpen: boolean;
// eslint-disable-next-line @typescript-eslint/ban-types
onSubmit: Function;
close: () => void;
tabIds: ReadonlyArray<string>;
allowDelete: boolean;
}) => {
return (
<ModalFormCard
omitFooter
isOpen={isOpen}
widthInPx="530px"
formId={formId}
close={close}
cardProps={{ bodySx: { p: 0 } }}
onSubmit={(values) => {
onSubmit(values);
}}
initialValues={{
id: "",
actionType: null,
}}
validate={({ id }) => {
if (!id) {
return {
id: "Tab ID is required",
};
}
if (tabIds.includes(id.toLowerCase())) {
return {
id: "Tab exists already",
};
}
}}
content={{
title,
}}
>
{({ errors, values, setFieldValue }) => (
<Box>
<Box sx={{ px: 4, py: 4 }}>
<InputBox
name="id"
label="Update Tab ID"
placeholder="Tab"
error={errors.id}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setFieldValue("id", e.target.value.trim());
setFieldValue("actionType", ActionType.UPDATE);
}}
/>
<Button
type="button"
sx={{ mt: 3, width: "100%" }}
onClick={() => {
if (values.id && values.id.length) {
onSubmit({
id: values.id,
actionType: ActionType.UPDATE,
});
}
close();
}}
>
Save
</Button>
</Box>
<Box
as="hr"
sx={{
borderBottom: "none",
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
borderTop: (theme) => `1px solid ${theme?.colors?.borders}`,
}}
/>
{allowDelete && (
<Box sx={{ px: 4, py: 4 }}>
<Heading as="h4">Delete this tab?</Heading>
<Text as="p" color="textClear" sx={{ mt: 2 }}>
This action cannot be undone.
</Text>
<Button
type="button"
variant="buttons.actionDelete"
sx={{ mt: 3 }}
onClick={() => {
onSubmit({
id: values.id,
actionType: ActionType.DELETE,
});
close();
}}
>
Yes, delete tab
</Button>
</Box>
)}
</Box>
)}
</ModalFormCard>
);
}
Example #18
Source File: index.tsx From slice-machine with Apache License 2.0 | 4 votes |
ReviewModal: React.FunctionComponent = () => {
const libraries = useContext(LibrariesContext);
const {
env,
isReviewLoading,
isLoginModalOpen,
hasSendAReview,
hasDoneTheOnboarding,
customTypeCount,
} = useSelector((store: SliceMachineStoreType) => ({
env: getEnvironment(store),
isReviewLoading: isLoading(store, LoadingKeysEnum.REVIEW),
isLoginModalOpen: isModalOpen(store, ModalKeysEnum.LOGIN),
hasSendAReview: userHasSendAReview(store),
hasDoneTheOnboarding: userHasDoneTheOnboarding(store),
customTypeCount: selectCustomTypeCount(store),
}));
const { skipReview, sendAReview, startLoadingReview, stopLoadingReview } =
useSliceMachineActions();
const sliceCount =
libraries && libraries.length
? libraries.reduce((count, lib) => {
if (!lib) {
return count;
}
return count + lib.components.length;
}, 0)
: 0;
const userHasCreateEnoughContent = sliceCount >= 1 && customTypeCount >= 1;
const onSendAReview = (rating: number, comment: string): void => {
startLoadingReview();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
Tracker.get().trackReview(env.framework, rating, comment);
sendAReview();
stopLoadingReview();
};
const validateReview = ({ rating }: { rating: number; comment: string }) => {
if (!rating) {
return { id: "Please Choose a rating" };
}
};
return (
<SliceMachineModal
isOpen={
userHasCreateEnoughContent && !hasSendAReview && hasDoneTheOnboarding
}
shouldCloseOnOverlayClick={false}
onRequestClose={() => skipReview()}
closeTimeoutMS={500}
contentLabel={"Review Modal"}
portalClassName={"ReviewModal"}
style={{
content: {
display: "flex",
position: "initial",
padding: "none",
top: "initial",
left: "initial",
minHeight: "initial",
},
overlay: {
top: "initial",
left: "initial",
right: 32,
bottom: 32,
position: "absolute",
height: "fit-content",
width: "fit-content",
backgroundColor: "unset",
},
}}
>
<Formik
validateOnMount
validateOnChange
initialValues={{
rating: 0,
comment: "",
}}
validate={validateReview}
onSubmit={(values) => {
onSendAReview(values.rating, values.comment);
}}
>
{({ isValid, values }) => (
<Form id="review-form">
<Card>
<Flex
sx={{
p: "16px",
pl: 4,
bg: "headSection",
alignItems: "center",
justifyContent: "space-between",
borderRadius: "8px 8px 0px 0px",
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
borderBottom: (t) => `1px solid ${t.colors?.borders}`,
}}
>
<Heading sx={{ fontSize: "20px", mr: 4 }}>
Give us your opinion
</Heading>
<Close
type="button"
onClick={() => skipReview()}
data-cy="close-review"
/>
</Flex>
<Flex
sx={{
flexDirection: "column",
padding: "16px 24px 32px",
bg: "headSection",
}}
>
<Text variant={"xs"} as={"p"} sx={{ maxWidth: 302, mb: 3 }}>
Overall, how difficult was your first experience using
Slicemachine?
</Text>
<Box
mb={2}
sx={{
display: "flex",
flex: 1,
justifyContent: "space-between",
}}
>
<Text variant={"xs"} as={"p"}>
Very difficult
</Text>
<Text variant={"xs"} as={"p"}>
Very easy
</Text>
</Box>
<Field name={"rating"} component={SelectReviewComponent} />
<Field
name={"comment"}
type="text"
placeholder={
"Sorry about that! What did you find the most difficult?"
}
as={Textarea}
autoComplete="off"
className={
values.rating >= 5 || values.rating === 0 ? "hidden" : ""
}
sx={{
height: 80,
opacity: 1,
mb: 3,
transition: "all 300ms",
"&.hidden": {
height: 0,
opacity: 0,
mb: 0,
p: 0,
border: "none",
},
}}
/>
<Button
form={"review-form"}
type="submit"
disabled={!isValid || isReviewLoading || isLoginModalOpen}
>
Submit
</Button>
</Flex>
</Card>
</Form>
)}
</Formik>
</SliceMachineModal>
);
}
Example #19
Source File: index.tsx From slice-machine with Apache License 2.0 | 4 votes |
function ModalCard<Values>({
children,
close,
isOpen,
formId,
validate,
onSubmit,
widthInPx,
initialValues,
content: { title },
cardProps,
omitFooter = false,
isLoading = false,
buttonLabel = "Save",
dataCy,
}: ModalCardProps<Values>): JSX.Element {
Modal.setAppElement("#__next");
return (
<SliceMachineModal
isOpen={isOpen}
shouldCloseOnOverlayClick
onRequestClose={close}
contentLabel={title}
style={{
content: {
width: widthInPx || "900px",
},
}}
>
<Formik
validateOnChange
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
initialValues={initialValues}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
validate={(values) => (validate ? validate(values) : undefined)}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
onSubmit={(values) => {
onSubmit(values);
close();
}}
>
{({
isValid,
isSubmitting,
values,
errors,
touched,
setFieldValue,
}) => (
<Form id={formId} {...(dataCy ? { "data-cy": dataCy } : null)}>
<Card
borderFooter
footerSx={{ p: 3 }}
bodySx={{ px: 4, py: 4 }}
sx={{ border: "none" }}
{...cardProps}
Header={({ radius }: { radius: string | number }) => (
<Flex
sx={{
p: "16px",
pl: 4,
bg: "headSection",
alignItems: "center",
justifyContent: "space-between",
borderTopLeftRadius: radius,
borderTopRightRadius: radius,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
borderBottom: (t) => `1px solid ${t.colors?.borders}`,
}}
>
<Heading sx={{ fontSize: "20px" }}>{title}</Heading>
<Close type="button" onClick={close} />
</Flex>
)}
Footer={
!omitFooter ? (
<Flex sx={{ alignItems: "space-between" }}>
<Box sx={{ ml: "auto" }} />
<ThemeButton
mr={2}
type="button"
onClick={close}
variant="secondary"
>
Cancel
</ThemeButton>
<Button
form={formId}
type="submit"
disabled={!isValid || isSubmitting || isLoading}
isLoading={isLoading}
>
{buttonLabel}
</Button>
</Flex>
) : null
}
>
{children({
isValid,
isSubmitting,
values,
errors,
touched,
setFieldValue,
})}
</Card>
</Form>
)}
</Formik>
</SliceMachineModal>
);
}
Example #20
Source File: Token.tsx From nft-market with MIT License | 4 votes |
Token = ({ token, isOnSale, onTransfer, onBuy, onSale }: TokenCompProps) => {
const [transfer, setTransfer] = useState<boolean>(false)
const [onSaleActive, setOnSale] = useState<boolean>(false)
const [address, setAddress] = useState<string>('')
const [price, setPrice] = useState<string>('')
const { user, ethPrice, contractDetails, transferToken, buyToken, setTokenSale } = useAppState()
const onTransferClick = async (e: FormEvent | MouseEvent) => {
e.preventDefault()
if (onTransfer && utils.isAddress(address)) {
transferToken(token.id, address)
setTransfer(false)
}
}
const onBuyClick = (e: MouseEvent) => {
e.preventDefault()
onBuy && buyToken(token.id, token.price)
}
const onSaleClick = async (e: MouseEvent) => {
e.preventDefault()
if (!onSale) return
try {
await setTokenSale(token.id, utils.parseEther(price), true)
setOnSale(false)
} catch (e) {
throw e
}
}
const { data: owner } = useSWR(token.id, fetchOwner)
const { data } = useSWR(`${METADATA_API}/token/${token.id}`, fetcherMetadata)
const tokenPriceEth = formatPriceEth(token.price, ethPrice)
if (!data)
return (
<Card variant="nft">
<Spinner />
</Card>
)
if (!data.name) return null
return (
<Card variant="nft">
<Image
sx={{ width: '100%', bg: 'white', borderBottom: '1px solid black' }}
src={data.image}
/>
<Box p={3} pt={2}>
<Heading as="h2">{data.name}</Heading>
<Divider variant="divider.nft" />
<Box>
<Text sx={{ color: 'lightBlue', fontSize: 1, fontWeight: 'bold' }}>Price</Text>
<Heading as="h3" sx={{ color: 'green', m: 0, fontWeight: 'bold' }}>
{constants.EtherSymbol} {Number(utils.formatEther(token.price)).toFixed(2)}{' '}
<Text sx={{ color: 'navy' }} as="span" variant="text.body">
({tokenPriceEth})
</Text>
</Heading>
{owner && typeof owner === 'string' && !onTransfer && (
<Box mt={2}>
<Text as="p" sx={{ color: 'lightBlue', fontSize: 1, fontWeight: 'bold' }}>
Owner
</Text>
<NavLink
target="_blank"
href={`https://rinkeby.etherscan.io/address/${owner}`}
variant="owner"
style={{
textOverflow: 'ellipsis',
width: '100%',
position: 'relative',
overflow: 'hidden',
}}
>
{toShort(owner)}
</NavLink>
</Box>
)}
<Box mt={2}>
<NavLink
target="_blank"
href={`https://testnets.opensea.io/assets/${contractDetails?.address}/${token.id}`}
variant="openSea"
>
View on Opensea.io
</NavLink>
</Box>
</Box>
{onTransfer && (
<Flex mt={3} sx={{ justifyContent: 'center' }}>
{transfer && (
<Box sx={{ width: '100%' }}>
<Flex
onSubmit={onTransferClick}
sx={{ width: '100%', flexDirection: 'column' }}
as="form"
>
<Input
onChange={e => setAddress(e.currentTarget.value)}
placeholder="ETH Address 0x0..."
/>
</Flex>
<Flex mt={2}>
<Button sx={{ bg: 'green' }} onClick={onTransferClick} variant="quartiary">
Confirm
</Button>
<Button
sx={{ bg: 'red' }}
ml={2}
onClick={() => setTransfer(false)}
variant="quartiary"
>
Cancel
</Button>
</Flex>
</Box>
)}
{onSaleActive && (
<Box sx={{ width: '100%' }}>
<Flex
onSubmit={onTransferClick}
sx={{ width: '100%', flexDirection: 'column' }}
as="form"
>
<Input
onChange={e => setPrice(e.currentTarget.value)}
placeholder="Token Price in ETH"
/>
</Flex>
<Flex mt={2}>
<Button sx={{ bg: 'green' }} onClick={onSaleClick} variant="quartiary">
Confirm
</Button>
<Button
sx={{ bg: 'red' }}
ml={2}
onClick={() => setOnSale(false)}
variant="quartiary"
>
Cancel
</Button>
</Flex>
</Box>
)}
{!transfer && !onSaleActive && (
<Flex sx={{ flexDirection: 'column', width: '100%', justifyContent: 'center' }}>
<Button onClick={() => setTransfer(!transfer)} variant="tertiary">
Transfer
</Button>
{isOnSale ? (
<Button
mt={2}
onClick={() => onSale && setTokenSale(token.id, token.price, false)}
variant="tertiary"
>
Remove from Sale
</Button>
) : (
<Button mt={2} onClick={() => setOnSale(!onSaleActive)} variant="tertiary">
Put Token for Sale
</Button>
)}
</Flex>
)}
</Flex>
)}
{onBuy && (
<Flex mt={3} sx={{ justifyContent: 'center', width: '100%' }}>
<Button
sx={{
opacity: !!user?.ownedTokens.find(
a => utils.formatUnits(a.id) === utils.formatUnits(token.id)
)
? 0.5
: 1,
pointerEvents: !!user?.ownedTokens.find(
a => utils.formatUnits(a.id) === utils.formatUnits(token.id)
)
? 'none'
: 'visible',
}}
onClick={onBuyClick}
variant="quartiary"
>
Buy Token
</Button>
</Flex>
)}
</Box>
</Card>
)
}
Example #21
Source File: index.tsx From slice-machine with Apache License 2.0 | 4 votes |
LoginModal: React.FunctionComponent = () => {
Modal.setAppElement("#__next");
const { env, isOpen, isLoginLoading } = useSelector(
(store: SliceMachineStoreType) => ({
isOpen: isModalOpen(store, ModalKeysEnum.LOGIN),
isLoginLoading: isLoading(store, LoadingKeysEnum.LOGIN),
env: getEnvironment(store),
})
);
const { closeLoginModal, startLoadingLogin, stopLoadingLogin, openToaster } =
useSliceMachineActions();
const prismicBase = preferWroomBase(env.manifest.apiEndpoint);
const loginRedirectUrl = `${
buildEndpoints(prismicBase).Dashboard.cliLogin
}&port=${new URL(env.sliceMachineAPIUrl).port}&path=/api/auth`;
const onClick = async () => {
if (!loginRedirectUrl) {
return;
}
try {
startLoadingLogin();
await startAuth();
window.open(loginRedirectUrl, "_blank");
const { shortId, intercomHash } = await startPolling<
CheckAuthStatusResponse,
ValidAuthStatus
>(
checkAuthStatus,
(status: CheckAuthStatusResponse): status is ValidAuthStatus =>
status.status === "ok" &&
Boolean(status.shortId) &&
Boolean(status.intercomHash),
3000,
60
);
void Tracker.get().identifyUser(shortId, intercomHash);
openToaster("Logged in", ToasterType.SUCCESS);
stopLoadingLogin();
closeLoginModal();
} catch (e) {
stopLoadingLogin();
openToaster("Logging fail", ToasterType.ERROR);
}
};
return (
<SliceMachineModal
isOpen={isOpen}
shouldCloseOnOverlayClick
onRequestClose={closeLoginModal}
contentLabel={"login_modal"}
style={{
content: {
position: "static",
display: "flex",
margin: "auto",
minHeight: "initial",
},
overlay: {
display: "flex",
},
}}
>
<Card>
<Flex
sx={{
p: "16px",
bg: "headSection",
alignItems: "center",
justifyContent: "space-between",
borderRadius: "8px 8px 0px 0px",
borderBottom: (t) => `1px solid ${String(t.colors?.borders)}`,
}}
>
<Heading sx={{ fontSize: "16px" }}>You're not connected</Heading>
<Close sx={{ p: 0 }} type="button" onClick={closeLoginModal} />
</Flex>
<Flex
sx={{
flexDirection: "column",
p: 3,
justifyContent: "center",
alignItems: "stretch",
}}
>
<Text
variant={"xs"}
sx={{
mb: 3,
maxWidth: 280,
textAlign: "center",
}}
>
{isLoginLoading ? (
<>
Not seeing the browser tab? <br />
<Link target={"_blank"} href={loginRedirectUrl}>
Click here
</Link>
</>
) : (
<>
Your session has expired.
<br />
Please log in again.
</>
)}
</Text>
<Button
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: 240,
mb: 3,
}}
onClick={() => void onClick()}
>
{isLoginLoading ? (
<Spinner color="#FFF" size={16} />
) : (
<>Signin to Prismic</>
)}
</Button>
</Flex>
</Card>
</SliceMachineModal>
);
}
Example #22
Source File: ChatWindow.tsx From chat-window with MIT License | 4 votes |
render() {
const {
title = 'Welcome!',
subtitle = 'How can we help you?',
newMessagePlaceholder = 'Start typing...',
emailInputPlaceholder = 'Enter your email',
agentAvailableText = "We're online right now!",
agentUnavailableText = "We're away at the moment.",
newMessagesNotificationText = 'View new messages',
companyName,
isMobile = false,
isCloseable = true,
showAgentAvailability = false,
accountId,
baseUrl,
} = this.props;
const {
customerId,
messages = [],
availableAgents = [],
isSending,
isOpen,
isTransitioning,
isGameMode,
shouldDisplayNotifications,
shouldDisplayBranding,
} = this.state;
if (isGameMode) {
return (
<EmbeddedGame
isMobile={isMobile}
onLoadGame={this.handleGameLoaded}
onLeaveGame={this.handleLeaveGameMode}
/>
);
}
if (isTransitioning) {
return null; // TODO: need to figure out the best way to handle this
}
if (!isOpen && shouldDisplayNotifications) {
return (
<UnreadMessages
messages={this.getUnreadMessages()}
newMessagesNotificationText={newMessagesNotificationText}
isMobile={isMobile}
onOpen={this.emitOpenWindow}
/>
);
}
// FIXME: only return null for versions of the chat-widget after v1.1.0
if (!isOpen && !this.isOnDeprecatedVersion()) {
return null;
}
const shouldAskForEmail = this.askForEmailUpfront();
const hasAvailableAgents = availableAgents.length > 0;
const replies = this.getQuickReplies(messages);
return (
<Flex
className={isMobile ? 'Mobile' : ''}
sx={{
bg: 'background',
flexDirection: 'column',
height: '100%',
width: '100%',
flex: 1,
}}
>
<Box sx={{bg: 'primary', position: 'relative'}}>
<Box pt={3} pb={showAgentAvailability ? 12 : 16} px={20}>
{/* TODO: wrap in a button element */}
{isCloseable && !this.isOnDeprecatedVersion() && (
<CloseIcon
className="CloseIcon"
width={24}
height={24}
onClick={this.emitCloseWindow}
/>
)}
<Heading
as="h2"
className="Papercups-heading"
sx={{color: 'background', my: 1, mr: 12}}
>
{title}
</Heading>
<Text sx={{color: 'offset'}}>{subtitle}</Text>
</Box>
{showAgentAvailability && (
<AgentAvailability
hasAvailableAgents={hasAvailableAgents}
agentAvailableText={agentAvailableText}
agentUnavailableText={agentUnavailableText}
/>
)}
</Box>
<Box
p={3}
sx={{
flex: 1,
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 21px 4px -20px inset',
overflowY: 'scroll',
}}
>
{messages.map((msg, key) => {
// Slight hack
const next = messages[key + 1];
const isLastInGroup = next
? msg.customer_id !== next.customer_id
: true;
const shouldDisplayTimestamp = key === messages.length - 1;
// NB: `msg.type` doesn't come from the server, it's just a way to
// help identify unsent messages in the frontend for now
const isMe = isCustomerMessage(msg, customerId);
return (
<motion.div
key={key}
initial={{opacity: 0, x: isMe ? 2 : -2}}
animate={{opacity: 1, x: 0}}
transition={{duration: 0.2, ease: 'easeIn'}}
>
<ChatMessage
key={key}
message={msg}
isMe={isMe}
companyName={companyName}
isLastInGroup={isLastInGroup}
shouldDisplayTimestamp={shouldDisplayTimestamp}
/>
</motion.div>
);
})}
{replies && replies.length > 0 ? (
<QuickReplies
replies={replies}
onSelect={this.handleSelectQuickReply}
/>
) : null}
<div ref={(el) => (this.scrollToEl = el)} />
</Box>
{shouldDisplayBranding && <PapercupsBranding />}
<Box
px={2}
sx={{
borderTop: '1px solid rgb(230, 230, 230)',
// TODO: only show shadow on focus TextArea below
boxShadow: 'rgba(0, 0, 0, 0.1) 0px 0px 100px 0px',
}}
>
{/*
NB: we use a `key` prop here to force re-render on open so
that the input will auto-focus appropriately
*/}
<ChatFooter
key={isOpen ? 1 : 0}
accountId={accountId}
baseUrl={baseUrl}
placeholder={newMessagePlaceholder}
emailInputPlaceholder={emailInputPlaceholder}
isSending={isSending}
shouldRequireEmail={shouldAskForEmail}
onSendMessage={this.handleSendMessage}
/>
</Box>
<img
alt="Papercups"
src="https://papercups.s3.us-east-2.amazonaws.com/papercups-logo.svg"
width="0"
height="0"
/>
</Flex>
);
}