theme-ui#Flex TypeScript Examples

The following examples show how to use theme-ui#Flex. 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: index.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
FullPage: React.FunctionComponent<FlexProps> = ({ children }) => (
  <Flex
    sx={{
      height: "calc(100vh - 57px)",
      width: "100vw",
      alignItems: "center",
      justifyContent: "center",
    }}
  >
    {children}
  </Flex>
)
Example #2
Source File: folder-name.tsx    From desktop with MIT License 6 votes vote down vote up
export function FolderName({ sitePath }: IProps): JSX.Element {
  const folder = path.basename(sitePath)
  return (
    <Flex
      marginTop="2"
      sx={{
        alignItems: `center`,
        fontWeight: `body`,
        color: `grey.60`,
        fontSize: 0,
        lineHeight: `default`,
      }}
    >
      <MdFolderOpen
        sx={{ marginRight: 2, flexShrink: 0 }}
        aria-label="Folder:"
      />
      <span
        sx={{
          minWidth: 0, // needed for text truncation to work properly
          textOverflow: `ellipsis`,
          whiteSpace: `nowrap`,
          overflow: `hidden`,
        }}
      >
        {folder}
      </span>
    </Flex>
  )
}
Example #3
Source File: PapercupsBranding.tsx    From chat-window with MIT License 6 votes vote down vote up
PapercupsBranding = () => {
  return (
    <Flex m={2} sx={{justifyContent: 'center', alignItems: 'center'}}>
      <Link
        href="https://papercups.io?utm_source=papercups&utm_medium=chat&utm_campaign=chat-widget-link"
        target="_blank"
        rel="noopener noreferrer"
        sx={{
          color: 'gray',
          opacity: 0.8,
          transition: '0.2s',
          '&:hover': {opacity: 1},
        }}
      >
        Powered by Papercups
      </Link>
    </Flex>
  );
}
Example #4
Source File: Error.tsx    From nft-market with MIT License 6 votes vote down vote up
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 #5
Source File: index.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
ZoneHeader: React.FunctionComponent<ZoneHeaderProps> = ({
  Heading,
  Actions,
}) => (
  <Flex
    bg="grey02"
    sx={{
      pl: 3,
      pr: 2,
      py: 2,
      mb: 2,
      borderRadius: "6px",
      alignItems: "center",
      minHeight: "51px",
      justifyContent: "space-between",
    }}
  >
    <Flex sx={{ alignItems: "center" }}>{Heading}</Flex>
    <Flex sx={{ alignItems: "center" }}>{Actions}</Flex>
  </Flex>
)
Example #6
Source File: ChatMessage.tsx    From chat-window with MIT License 6 votes vote down vote up
PopupChatMessage = ({message}: Props) => {
  const {body, user, type} = message;
  const isBot = type === 'bot';
  const identifer = isBot ? 'Bot' : getAgentIdentifier(user);

  return (
    <Box pr={0} pl={0} pb={2}>
      <Flex
        sx={{justifyContent: 'flex-start', alignItems: 'center', width: '100%'}}
      >
        <SenderAvatar name={identifer} user={user} isBot={isBot} />

        <ChatMessageBody
          sx={{
            px: 3,
            py: 3,
            color: 'text',
            bg: 'background',
            whiteSpace: 'pre-wrap',
            flex: 1,
            border: '1px solid rgb(245, 245, 245)',
            boxShadow: 'rgba(35, 47, 53, 0.09) 0px 2px 8px 0px',
            maxWidth: '84%',
          }}
          content={body}
        />
      </Flex>
    </Box>
  );
}
Example #7
Source File: MetamaskLogin.tsx    From nft-market with MIT License 6 votes vote down vote up
MetamaskLogin = ({ onClickConnect }: MetamaskLoginProps) => {
  return (
    <Flex sx={{ flexDirection: 'column', alignItems: 'center' }}>
      <Button sx={{ maxWidth: 200, mt: 5 }} variant="quartiary" onClick={onClickConnect}>
        Sign in with
        <Image
          sx={{ width: 35, height: 35 }}
          ml={3}
          src="https://docs.metamask.io/metamask-fox.svg"
        />
      </Button>
    </Flex>
  )
}
Example #8
Source File: onboarding.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
WelcomeSlide = ({ onClick }: { onClick: () => void }) => {
  const { theme } = useThemeUI();

  return (
    <>
      <Flex sx={{ ...imageSx }}>
        <SliceMachineLogo
          width={imageSx.width}
          height={imageSx.height}
          fill={theme.colors?.purple as string}
        />
      </Flex>
      <Header>Welcome to Slice Machine</Header>
      <SubHeader>Prismic’s local component development tool</SubHeader>
      <Button data-cy="get-started" onClick={onClick} title="start onboarding">
        Get Started
      </Button>
    </>
  );
}
Example #9
Source File: AgentAvailability.tsx    From chat-window with MIT License 6 votes vote down vote up
AgentAvailability = ({
  hasAvailableAgents,
  agentAvailableText,
  agentUnavailableText,
}: {
  hasAvailableAgents: boolean;
  agentAvailableText: string;
  agentUnavailableText: string;
}) => {
  return (
    <Flex
      px={20}
      py={1}
      sx={{
        bg: 'lighter',
        borderTop: '1px solid rgba(230, 230, 230, 0.25)',
        alignItems: 'center',
      }}
    >
      <Box
        mr={2}
        sx={{
          height: 8,
          width: 8,
          bg: hasAvailableAgents ? 'green' : 'muted',
          border: '1px solid #fff',
          borderRadius: '50%',
        }}
      ></Box>
      <Text sx={{color: 'offset', fontSize: 12}}>
        {hasAvailableAgents ? agentAvailableText : agentUnavailableText}
      </Text>
    </Flex>
  );
}
Example #10
Source File: Identicon.tsx    From nft-market with MIT License 6 votes vote down vote up
Identicon = ({ address, size = 16 }: IdenticonProps) => {
  const ref = useRef<HTMLDivElement>(null)
  useEffect(() => {
    if (!ref.current) return
    try {
      ref.current.innerHTML = ''
      ref.current.appendChild(jazzicon(size, parseInt(address.slice(2, 10), 16)))
    } catch (e) {
      console.log(e)
    }
  }, [address, size])

  return (
    <Flex
      ref={ref}
      sx={{
        justifyContent: 'center',
        width: size + 2,
      }}
    />
  )
}
Example #11
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
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 #12
Source File: Login.tsx    From nft-market with MIT License 5 votes vote down vote up
Login = () => {
  const { activatingConnector, setActivatingConnector } = useAppState()
  const { connector, activate } = useWeb3React()
  return (
    <Flex sx={{ justifyContent: 'center' }}>
      {Object.keys(connectorsByName).map((name: string) => {
        const currentConnector = connectorsByName[name as keyof typeof connectorsByName]
        const activating = currentConnector === activatingConnector
        const connected = currentConnector === connector

        return (
          <Button
            mt={2}
            mr={2}
            variant="connect"
            sx={{
              borderColor: activating ? 'orange' : connected ? 'green' : 'unset',
              position: 'relative',
              maxWidth: 250,
            }}
            key={name}
            onClick={() => {
              setActivatingConnector(currentConnector)
              activate(connectorsByName[name as keyof typeof connectorsByName] as AbstractConnector)
            }}
          >
            {iconsMap[name as keyof typeof connectorsByName] && (
              <Image
                sx={{ width: 35, height: 35 }}
                mr={3}
                src={iconsMap[name as keyof typeof connectorsByName]}
              />
            )}

            {name}
            {activating && <Spinner size={20} color="white" sx={{ ml: 3 }} />}
          </Button>
        )
      })}
    </Flex>
  )
}
Example #13
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
CustomTypes: React.FunctionComponent = () => {
  const { openCreateCustomTypeModal } = useSliceMachineActions();
  const { customTypes, isCreatingCustomType, customTypeCount } = useSelector(
    (store: SliceMachineStoreType) => ({
      customTypes: selectAllCustomTypes(store),
      customTypeCount: selectCustomTypeCount(store),
      isCreatingCustomType: isLoading(
        store,
        LoadingKeysEnum.CREATE_CUSTOM_TYPE
      ),
    })
  );

  return (
    <Container sx={{ flex: 1, display: "flex", flexDirection: "column" }}>
      <Header
        ActionButton={
          customTypeCount > 0 ? (
            <Button
              data-cy="create-ct"
              onClick={openCreateCustomTypeModal}
              sx={{
                minWidth: "171px",
              }}
            >
              {isCreatingCustomType ? (
                <Spinner color="#FFF" size={14} />
              ) : (
                "Create a Custom Type"
              )}
            </Button>
          ) : undefined
        }
        MainBreadcrumb={
          <Fragment>
            <MdSpaceDashboard /> <Text ml={2}>Custom Types</Text>
          </Fragment>
        }
        breadrumbHref="/"
      />
      {customTypeCount === 0 ? (
        <Flex
          sx={{
            flex: 1,
            justifyContent: "center",
            alignItems: "center",
          }}
        >
          <EmptyState
            title={"What are Custom Types?"}
            onCreateNew={openCreateCustomTypeModal}
            isLoading={isCreatingCustomType}
            buttonText={"Create one"}
            documentationComponent={
              <>
                Custom Types are models for your documents. They are the place
                where you define and configure Fields and Slices for your
                content. They will be stored locally, and you will be able to
                push them to your repository.{" "}
                <ThemeLink
                  target={"_blank"}
                  href={"https://prismic.io/docs/core-concepts/custom-types "}
                  sx={(theme) => ({ color: theme?.colors?.primary })}
                >
                  Learn more
                </ThemeLink>
                .
              </>
            }
          />
        </Flex>
      ) : (
        <CustomTypeTable customTypes={customTypes} />
      )}
      <CreateCustomTypeModal />
    </Container>
  );
}
Example #14
Source File: ChatMessage.tsx    From chat-window with MIT License 5 votes vote down vote up
SenderAvatar = ({
  name,
  user,
  isBot,
}: {
  name: string;
  user?: User;
  isBot?: boolean;
}) => {
  const profilePhotoUrl = user && user.profile_photo_url;

  if (profilePhotoUrl) {
    return (
      <Box
        mr={2}
        style={{
          height: 32,
          width: 32,
          borderRadius: '50%',
          justifyContent: 'center',
          alignItems: 'center',

          backgroundPosition: 'center',
          backgroundSize: 'cover',
          backgroundImage: `url(${profilePhotoUrl})`,
        }}
      />
    );
  }

  return (
    <Flex
      mr={2}
      sx={{
        bg: isBot ? 'lighter' : 'primary',
        height: 32,
        width: 32,
        borderRadius: '50%',
        justifyContent: 'center',
        alignItems: 'center',
        color: '#fff',
      }}
    >
      {isBot && name.toLowerCase() === 'bot' ? (
        <BotIcon fill="background" height={16} width={16} />
      ) : (
        name.slice(0, 1).toUpperCase()
      )}
    </Flex>
  );
}
Example #15
Source File: Desktop.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
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: [hash].tsx    From desktop with MIT License 5 votes vote down vote up
function SiteDetails({ site }: { site: GatsbySite }): JSX.Element {
  const { running, port, status } = useSiteRunnerStatus(site)

  const version = site.gatsbyVersion

  const adminSupported = useMemo(() => version && supportsAdmin(version), [
    version,
  ])

  if (!adminSupported) {
    return (
      <Flex
        sx={{
          alignItems: `center`,
          justifyContent: `center`,
          width: `100%`,
          height: `100%`,
        }}
      >
        <EmptyState
          heading="Please upgrade Gatsby"
          text={`Your site's version of Gatsby does not support Gatsby Admin. Please upgrade to the latest version`}
        />
      </Flex>
    )
  }

  return (
    <Flex sx={{ height: `100%` }}>
      {running && status !== GlobalStatus.InProgress && port ? (
        <iframe
          frameBorder={0}
          src={`http://localhost:${port}/___admin/`}
          sx={{
            flex: 1,
          }}
        />
      ) : (
        <Flex
          sx={{
            alignItems: `center`,
            justifyContent: `center`,
            width: `100%`,
            height: `100%`,
          }}
        >
          <div sx={{ maxWidth: `20rem` }}>
            <EmptyState
              heading="This site is not running"
              text={`Please start the gatsby develop process in order to use Gatsby \u000A Admin for this site.`}
              primaryAction={
                status === GlobalStatus.InProgress ? (
                  <Button variant="PRIMARY" size="M" loading={true} />
                ) : (
                  <SiteActions site={site} variant="PRIMARY" size="M" />
                )
              }
            />
          </div>
        </Flex>
      )}
    </Flex>
  )
}
Example #17
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
export default function Changelog() {
  const { changelog, packageManager } = useSelector(
    (store: SliceMachineStoreType) => ({
      changelog: getChangelog(store),
      packageManager: getPackageManager(store),
    })
  );

  // Null is when no version are found (edge case)
  const [selectedVersion, setSelectedVersion] = useState<PackageVersion | null>(
    changelog.versions[0] || null
  );

  return (
    <Flex
      sx={{
        maxWidth: "1224px",
      }}
    >
      <Navigation
        changelog={changelog}
        selectedVersion={selectedVersion}
        selectVersion={(version) => setSelectedVersion(version)}
      />

      {changelog.versions.length === 0 || !selectedVersion ? (
        <Flex
          sx={{
            width: "650px",
            minWidth: "650px",
            height: "100%",
            borderRight: "1px solid",
            borderColor: "grey01",
            flexDirection: "column",
            padding: "24px 32px",
            gap: "24px",
          }}
        >
          <ReleaseWarning />
        </Flex>
      ) : (
        <VersionDetails
          changelog={changelog}
          selectedVersion={selectedVersion}
          packageManager={packageManager}
        />
      )}
    </Flex>
  );
}
Example #18
Source File: tab-navigation.tsx    From desktop with MIT License 5 votes vote down vote up
export function TabNavigation(): JSX.Element {
  const { siteTabs } = useSiteTabs()
  return (
    <Flex
      as="nav"
      sx={{
        backgroundColor: `purple.90`,
      }}
      css={{
        WebkitAppRegion: `drag`,
        WebkitUserSelect: `none`,
        paddingLeft: 88,
      }}
    >
      <Link
        to="/sites"
        activeClassName="active"
        sx={{
          display: `flex`,
          alignItems: `center`,
          py: 3,
          px: 4,
          "&.active": {
            backgroundColor: `white`,
          },
          cursor: `pointer`,
        }}
        css={{ WebkitAppRegion: `no-drag` }}
        aria-label="All sites"
      >
        <img
          src={require(`../../assets/tinyicon.svg`)}
          width={16}
          height={16}
          alt=""
        />
      </Link>
      {siteTabs.map((site) => (
        <SiteTabLink key={site.hash} site={site} />
      ))}
    </Flex>
  )
}
Example #19
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
VersionDetails: React.FC<VersionDetailsProps> = ({
  changelog,
  selectedVersion,
  packageManager,
}) => {
  return (
    <Flex
      sx={{
        width: "650px",
        minWidth: "650px",
        height: "100%",
        borderRight: "1px solid",
        borderColor: "grey01",
        flexDirection: "column",
      }}
    >
      <Flex
        sx={{
          padding: "32px",
          borderBottom: "1px solid",
          borderColor: "grey01",
          justifyContent: "space-between",
          alignItems: "center",
        }}
      >
        <Text
          sx={{
            fontSize: "24px",
            fontWeight: 600,
            lineHeight: "32px",
          }}
        >
          {`Version ${selectedVersion.versionNumber}`}
        </Text>
        {!!selectedVersion.kind && (
          <VersionKindLabel versionKind={selectedVersion.kind} />
        )}
      </Flex>

      <Flex
        sx={{
          flexDirection: "column",
          padding: "24px 32px",
          gap: "24px",
        }}
      >
        {selectedVersion.releaseNote?.includes("# Breaking Change") && (
          <Flex
            sx={{
              padding: "16px",
              bg: "lightOrange",
              color: "darkOrange",
              fontSize: "13px",
              lineHeight: "24px",
              borderRadius: "4px",
              gap: "16px",
            }}
            data-testid="breaking-changes-warning"
          >
            <AiFillWarning size="24px" />
            This update includes breaking changes. To update correctly, follow
            the steps below.
          </Flex>
        )}

        <UpdateCommandBox
          changelog={changelog}
          selectedVersion={selectedVersion}
          packageManager={packageManager}
        />
        {selectedVersion?.releaseNote ? (
          <ReleaseNoteDetails releaseNote={selectedVersion.releaseNote} />
        ) : (
          <ReleaseWarning />
        )}
      </Flex>
    </Flex>
  );
}
Example #20
Source File: tab-navigation.tsx    From desktop with MIT License 5 votes vote down vote up
export function SiteTabLink({ site, ...props }: ITabProps): JSX.Element {
  const { removeTab } = useSiteTabs()

  const location = useLocation()

  const url = `/sites/${site.hash}`

  const isActive = location.pathname === url

  const remove = useCallback(() => {
    if (isActive) {
      navigate(`/sites`)
    }
    removeTab(site.hash)
  }, [removeTab, site, isActive])

  return (
    <Flex
      sx={{
        alignItems: `center`,
        pr: 2,
        py: 3,
        ...(isActive && {
          backgroundColor: `purple.80`,
          color: `white`,
        }),
      }}
    >
      <TabLink {...props} to={url}>
        <SiteStatusDot status={site.siteStatus.status} sx={{ mr: 2 }} />
        {site.name}
      </TabLink>
      <button
        onClick={remove}
        aria-label="Close tab"
        sx={{
          p: 3,
          background: `none`,
          border: `none`,
          fontFamily: `sans`,
          fontWeight: 500,
          textDecoration: `none`,
          color: `primaryBackground`,
          display: `flex`,
          alignItems: `center`,
        }}
      >
        <MdClear />
      </button>
    </Flex>
  )
}
Example #21
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
Header: React.FunctionComponent<PropTypes> = ({
  title,
  Model,
  variation,
  handleScreenSizeChange,
  size,
}) => {
  return (
    <Box
      sx={{
        p: 3,
        display: "grid",
        gridTemplateColumns: "repeat(3, 1fr)",
        gridTemplateRows: "1fr",
        borderBottom: "1px solid #F1F1F1",
      }}
    >
      <Flex
        sx={{
          alignItems: "center",
        }}
      >
        <Text mr={2}>{title}</Text>
        {Model.variations.length > 1 ? (
          <VarationsPopover
            buttonSx={{ p: 1 }}
            defaultValue={variation}
            variations={Model.variations}
            onChange={(v) => redirect(Model, v, true)}
          />
        ) : null}
      </Flex>
      <Flex
        sx={{
          alignItems: "center",
          justifyContent: "space-around",
        }}
      >
        <ScreenSizes size={size} onClick={handleScreenSizeChange} />
      </Flex>
    </Box>
  );
}
Example #22
Source File: ModalMapSelect.tsx    From HappyIslandDesigner with MIT License 5 votes vote down vote up
export default function ModalMapSelect(){
  const [modalIsOpen,setIsOpen] = useState(false);
  function openModal() {
    setIsOpen(true);
  }

  function afterOpenModal() {

  }

  function closeModal(){
    if (!isMapEmpty())
      setIsOpen(false);
  }

  useEffect(() => {
    Modal.setAppElement('body');
  }, []);

  const refCallback = useBlockZoom();

  return (
    <div>
      <button id="open-map-select" style={{display: 'none'}} onClick={openModal}>Open Modal</button>
      <button id="close-map-select" style={{display: 'none'}} onClick={closeModal}>Open Modal</button>
      <Modal
        isOpen={modalIsOpen}
        closeTimeoutMS={200} // keep in sync with modal.scss
        onAfterOpen={afterOpenModal}
        onRequestClose={closeModal}
        style={customStyles}
        sx={{}}
        contentLabel="Example Modal"
      >
        <Flex
          ref={refCallback}
          p={3}
          sx={{
            backgroundColor : colors.paper.cssColor,
            border: 0,
            borderRadius: 8,
            flexDirection: 'column',
            overflow: 'auto',
            //borderRadius: 60,
            //minWidth: 260,
          }}>
          <Box p={2} sx={{
            backgroundColor: colors.level3.cssColor,
            borderRadius: '30px 4px 4px 30px',
          }}>
            <Image variant='block' sx={{maxWidth: 150}} src='static/img/nook-inc-white.png'/>
          </Box>
          <IslandLayoutSelector />
          <Box p={3} sx={{
            backgroundColor: colors.level3.cssColor,
            borderRadius: '4px 30px 30px 4px',
          }} />
        </Flex>
      </Modal>
    </div>
  );
}
Example #23
Source File: index.tsx    From slice-machine with Apache License 2.0 5 votes vote down vote up
export default function Simulator() {
  const { Model, variation } = useContext(SliceContext);

  const { framework, version, simulatorUrl } = useSelector(
    (state: SliceMachineStoreType) => ({
      framework: getFramework(state),
      simulatorUrl: selectSimulatorUrl(state),
      version: getCurrentVersion(state),
    })
  );

  useEffect(() => {
    void Tracker.get().trackOpenSliceSimulator(framework, version);
  }, []);

  const [state, setState] = useState({ size: Size.FULL });

  const handleScreenSizeChange = (screen: { size: Size }) => {
    setState({ ...state, size: screen.size });
  };

  if (!Model || !variation) {
    return <div />;
  }

  const sliceView = useMemo(
    () => [{ sliceID: Model.model.id, variationID: variation.id }],
    [Model.model.id, variation.id]
  );

  return (
    <Flex sx={{ height: "100vh", flexDirection: "column" }}>
      <Header
        title={Model.model.name}
        Model={Model}
        variation={variation}
        handleScreenSizeChange={handleScreenSizeChange}
        size={state.size}
      />
      <IframeRenderer
        size={state.size}
        simulatorUrl={simulatorUrl}
        sliceView={sliceView}
      />
    </Flex>
  );
}
Example #24
Source File: ModalMapSelect.tsx    From HappyIslandDesigner with MIT License 4 votes vote down vote up
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 #25
Source File: site-card.tsx    From desktop with MIT License 4 votes vote down vote up
/**
 * The item in the list of sites
 */
export function SiteCard({ site }: PropsWithChildren<IProps>): JSX.Element {
  const { status, port, rawLogs, logs, running } = useSiteRunnerStatus(site)

  const { addTab } = useSiteTabs()

  console.log(site.name, status)
  const displayStatus = getSiteDisplayStatus(status)

  const [editor] = useConfig(`preferredEditor`)

  const showManageInDesktop = running && !site.startedInDesktop
  // TODO add a proper condition to display Gatsby Admin setup instructions
  const showAdminInstructions = false

  return (
    <Flex
      as={`section`}
      sx={{
        border: `grey`,
        borderRadius: 2,
        boxShadow: `raised`,
        whiteSpace: `pre`,
      }}
    >
      <StatusIndicator displayStatus={displayStatus} />
      <Flex sx={{ p: 4, flexDirection: `column`, flex: 1 }}>
        <Flex
          css={{ justifyContent: `space-between`, minHeight: `24px` }}
          mb={5}
        >
          <span
            sx={{
              fontFamily: `sans`,
              fontWeight: 600,
              fontSize: 1,
              pr: 3,
            }}
          >
            {site.name ?? `Unnamed site`}
            <FolderName sitePath={site.root} />
          </span>
          <Flex sx={{ alignItems: `center` }}>
            {showManageInDesktop ? (
              <div sx={{ mr: 3 }}>
                <ManageInDesktop />
              </div>
            ) : showAdminInstructions ? (
              <div sx={{ mr: 3 }}>
                <SetupAdmin />
              </div>
            ) : (
              <Fragment>
                <span css={visuallyHiddenCss}>
                  Site status: {siteDisplayStatusLabels[displayStatus]}
                </span>
                <div sx={{ mr: 3 }}>
                  {displayStatus === SiteDisplayStatus.Running && !!port ? (
                    <SiteLauncher port={port} siteHash={site.hash} />
                  ) : displayStatus === SiteDisplayStatus.Starting ? (
                    <Text as="span" sx={{ fontSize: 0, color: `grey.60` }}>
                      Starting site...
                    </Text>
                  ) : null}
                </div>
                {!!rawLogs?.length && (
                  <LogsLauncher
                    structuredLogs={logs}
                    logs={rawLogs}
                    status={status}
                    siteName={site.name}
                    siteHash={site.hash}
                  />
                )}
              </Fragment>
            )}
            <SiteActions site={site} disabled={showManageInDesktop} />
          </Flex>
        </Flex>
        <Flex mt="auto">
          <EditorLauncher
            path={site.root}
            editor={editor}
            siteHash={site.hash}
          />
        </Flex>
      </Flex>
      <button
        sx={{
          display: `flex`,
          flexBasis: `32px`,
          alignItems: `center`,
          justifyContent: `center`,
          backgroundColor: `grey.10`,
          border: `none`,
          boxShadow: `-1px 0px 0px #D9D7E0`,
          cursor: `pointer`,
          color: `grey.50`,
          fontSize: 2,
        }}
        aria-label="Open site admin"
        onClick={(event): void => {
          event.stopPropagation()
          trackEvent(`CLICK_TO_OPEN_ADMIN_TAB`, { siteHash: site.hash })
          addTab(site.hash)
          navigate(`/sites/${site.hash}`)
        }}
      >
        <MdArrowForward />
      </button>
    </Flex>
  )
}
Example #26
Source File: Token.tsx    From nft-market with MIT License 4 votes vote down vote up
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 #27
Source File: slices.tsx    From slice-machine with Apache License 2.0 4 votes vote down vote up
SlicesIndex: React.FunctionComponent = () => {
  const libraries = useContext(LibrariesContext);
  const { openCreateSliceModal, closeCreateSliceModal, createSlice } =
    useSliceMachineActions();

  const { isCreateSliceModalOpen, isCreatingSlice, localLibs, remoteLibs } =
    useSelector((store: SliceMachineStoreType) => ({
      isCreateSliceModalOpen: isModalOpen(store, ModalKeysEnum.CREATE_SLICE),
      isCreatingSlice: isLoading(store, LoadingKeysEnum.CREATE_SLICE),
      localLibs: getLibraries(store),
      remoteLibs: getRemoteSlices(store),
    }));

  const _onCreate = ({
    sliceName,
    from,
  }: {
    sliceName: string;
    from: string;
  }) => {
    createSlice(sliceName, from);
  };

  const localLibraries: LibraryState[] | undefined = libraries?.filter(
    (l) => l.isLocal
  );

  const sliceCount = (libraries || []).reduce((count, lib) => {
    if (!lib) {
      return count;
    }

    return count + lib.components.length;
  }, 0);

  return (
    <>
      <Container
        sx={{
          display: "flex",
          flex: 1,
        }}
      >
        <Box
          as={"main"}
          sx={{
            flex: 1,
            display: "flex",
            flexDirection: "column",
          }}
        >
          <Header
            ActionButton={
              localLibraries?.length != 0 && sliceCount != 0 ? (
                <CreateSliceButton
                  onClick={openCreateSliceModal}
                  loading={isCreatingSlice}
                />
              ) : undefined
            }
            MainBreadcrumb={
              <>
                <MdHorizontalSplit /> <Text ml={2}>Slices</Text>
              </>
            }
            breadrumbHref="/slices"
          />
          {libraries && (
            <Flex
              sx={{
                flex: 1,
                flexDirection: "column",
              }}
            >
              {sliceCount === 0 ? (
                <Flex
                  sx={{
                    flex: 1,
                    justifyContent: "center",
                    alignItems: "center",
                  }}
                >
                  <EmptyState
                    title={"What are Slices?"}
                    onCreateNew={openCreateSliceModal}
                    isLoading={isCreatingSlice}
                    buttonText={"Create one"}
                    documentationComponent={
                      <>
                        Slices are sections of your website. Prismic documents
                        contain a dynamic "Slice Zone" that allows content
                        creators to add, edit, and rearrange Slices to compose
                        dynamic layouts for any page design.{" "}
                        <Link
                          target={"_blank"}
                          href={"https://prismic.io/docs/core-concepts/slices"}
                          sx={(theme) => ({ color: theme?.colors?.primary })}
                        >
                          Learn more
                        </Link>
                        .
                      </>
                    }
                  />
                </Flex>
              ) : (
                libraries.map((lib: LibraryState) => {
                  const { name, isLocal, components } = lib;
                  return (
                    <Flex
                      key={name}
                      sx={{
                        flexDirection: "column",
                        "&:not(last-of-type)": {
                          mb: 4,
                        },
                      }}
                    >
                      <Flex
                        sx={{
                          alignItems: "center",
                          justifyContent: "space-between",
                        }}
                      >
                        <Flex
                          sx={{
                            alignItems: "center",
                            fontSize: 3,
                            lineHeight: "48px",
                            fontWeight: "heading",
                            mb: 1,
                          }}
                        >
                          <Text>{name}</Text>
                        </Flex>
                        {!isLocal && <p>⚠️ External libraries are read-only</p>}
                      </Flex>
                      <Grid
                        elems={components.map(([e]) => e)}
                        defineElementKey={(slice: SliceState) =>
                          slice.model.name
                        }
                        renderElem={(slice: SliceState) => {
                          return SharedSlice.render({
                            displayStatus: true,
                            slice,
                          });
                        }}
                      />
                    </Flex>
                  );
                })
              )}
            </Flex>
          )}
        </Box>
      </Container>
      {localLibraries && localLibraries.length > 0 && (
        <CreateSliceModal
          isCreatingSlice={isCreatingSlice}
          isOpen={isCreateSliceModalOpen}
          close={closeCreateSliceModal}
          libraries={localLibs}
          remoteSlices={remoteLibs}
          onSubmit={({ sliceName, from }) => _onCreate({ sliceName, from })}
        />
      )}
    </>
  );
}
Example #28
Source File: ChatFooter.tsx    From chat-window with MIT License 4 votes vote down vote up
ChatFooter = ({
  placeholder,
  emailInputPlaceholder,
  isSending,
  shouldRequireEmail,
  accountId,
  baseUrl,
  onSendMessage,
}: {
  placeholder?: string;
  emailInputPlaceholder?: string;
  isSending: boolean;
  shouldRequireEmail?: boolean;
  accountId: string;
  baseUrl?: string;
  onSendMessage: (message: Partial<Message>, email?: string) => Promise<void>;
}) => {
  const [message, setMessage] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [isUploading, setIsUploading] = React.useState(false);
  const [error, setError] = React.useState<any>(null);
  const messageInput = React.useRef(null);

  const hasValidEmail = email && email.length > 5 && email.indexOf('@') !== -1;
  const isDisabled = isUploading || isSending;

  const handleMessageChange = (e: React.ChangeEvent<HTMLTextAreaElement>) =>
    setMessage(e.target.value);

  const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) =>
    setEmail(e.target.value);

  const handleSetEmail = (e?: React.FormEvent<HTMLFormElement>) => {
    e && e.preventDefault();

    if (messageInput.current) {
      messageInput.current.focus();
    }
  };

  const handleSendMessage = (e?: React.FormEvent<HTMLFormElement>) => {
    e && e.preventDefault();

    onSendMessage({body: message}, email);
    setMessage('');
    setEmail('');
  };

  const handleUploadStarted = () => setIsUploading(true);

  const handleUploadError = (err: any) => {
    setError(err);
    setIsUploading(false);
  };

  const handleUploadSuccess = ({data: file}: {data: Attachment}) => {
    if (file && file.id) {
      onSendMessage({body: message, file_ids: [file.id]}, email);
      setMessage('');
      setEmail('');
      setIsUploading(false);
      setError(null);
    }
  };

  const handleKeyDown = (e: any) => {
    const {key, shiftKey} = e;

    if (!shiftKey && key === 'Enter') {
      handleSendMessage(e);
    }
  };

  return (
    <Box>
      <form onSubmit={handleSetEmail}>
        {shouldRequireEmail && (
          <Box py={1} sx={{borderBottom: '1px solid rgb(230, 230, 230)'}}>
            <Input
              sx={{variant: 'styles.input.transparent'}}
              placeholder={emailInputPlaceholder}
              value={email}
              onChange={handleEmailChange}
            />
          </Box>
        )}
      </form>

      <form onSubmit={handleSendMessage}>
        <Flex sx={{alignItems: 'center'}} py={2}>
          <Box mr={2} sx={{flex: 1}}>
            <ResizableTextArea
              sx={{
                fontFamily: 'body',
                color: 'input',
                variant: 'styles.input.transparent',
              }}
              ref={messageInput}
              className="TextArea--transparent"
              placeholder={placeholder}
              minRows={1}
              maxRows={4}
              autoFocus
              value={message}
              disabled={isDisabled || (shouldRequireEmail && !hasValidEmail)}
              onKeyDown={handleKeyDown}
              onChange={handleMessageChange}
            />
          </Box>

          <Flex>
            <Upload
              action={`${baseUrl}/api/upload`}
              data={{account_id: accountId}}
              headers={{'X-Requested-With': null}}
              onStart={handleUploadStarted}
              onSuccess={handleUploadSuccess}
              onError={handleUploadError}
            >
              <Button
                variant="link"
                type="button"
                disabled={isDisabled}
                sx={{
                  display: 'flex',
                  justifyContent: 'center',
                  alignItems: 'center',
                  borderRadius: '50%',
                  height: '36px',
                  width: '36px',
                  padding: 0,
                }}
              >
                <PaperclipIcon
                  width={16}
                  height={16}
                  fill={error ? 'red' : 'gray'}
                />
              </Button>
            </Upload>

            <Button
              variant="primary"
              type="submit"
              disabled={isDisabled}
              sx={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                borderRadius: '50%',
                height: '36px',
                width: '36px',
                padding: 0,
              }}
            >
              <SendIcon width={16} height={16} fill="background" />
            </Button>
          </Flex>
        </Flex>
      </form>
    </Box>
  );
}
Example #29
Source File: onboarding.tsx    From slice-machine with Apache License 2.0 4 votes vote down vote up
export default function Onboarding(): JSX.Element {
  const STEPS = [
    <WelcomeSlide onClick={nextSlide} />,
    <BuildSlicesSlide />,
    <CreatePageTypesSlide />,
    <PushPagesSlide />,
  ];

  const { finishOnboarding } = useSliceMachineActions();

  const [state, setState] = useState({
    step: 0,
  });

  handleTracking({
    ...state,
    maxSteps: STEPS.length,
  });

  const finish = () => {
    finishOnboarding();
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
    router.push("/");
  };

  function nextSlide() {
    if (state.step === STEPS.length - 1) return finish();
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
    Tracker.get().trackOnboardingContinue(idFromStep(state.step));

    return setState({ ...state, step: state.step + 1 });
  }

  function prevSlide() {
    return setState({ ...state, step: state.step - 1 });
  }

  return (
    <OnboardingGrid>
      <Flex
        sx={{
          gridArea: "top-right",
          alignItems: "center",
          justifyContent: "end",
          padding: "1em 4em",
        }}
      >
        {!!state.step && (
          <Button
            variant="transparent"
            onClick={finish}
            data-cy="skip-onboarding"
            title="skip onboarding"
            tabIndex={0}
            sx={{
              color: "textClear",
            }}
          >
            skip
          </Button>
        )}
      </Flex>

      {STEPS.map((Component, i) => (
        <Flex
          hidden={i !== state.step}
          key={`step-${i + 1}`}
          sx={{
            gridArea: "content",
            alignItems: "center",
            justifyContent: "center",
            alignContent: "center",
            flexDirection: "column",
            opacity: i === state.step ? "1" : "0",
            pointerEvents: i === state.step ? "all" : "none",
            transition: `opacity .2s ease-in`,
          }}
        >
          {Component}
        </Flex>
      ))}

      <Flex
        sx={{
          gridArea: "footer",
          alignItems: "start",
          justifyContent: "center",
          padingTop: "16px", // half height of a button
        }}
      >
        {!!state.step && (
          <StepIndicator current={state.step - 1} maxSteps={STEPS.length - 1} />
        )}
      </Flex>

      <Flex
        sx={{
          gridArea: "footer-left",
          alignItems: "start",
          justifyContent: "space-around",
        }}
      >
        {state.step >= 2 && (
          <IconButton
            tabIndex={0}
            title="previous slide"
            sx={{
              width: "40px",
              height: "40px",
              borderRadius: "50%",
              background: "#F1F1F4",
              border: "1px solid rgba(62, 62, 72, 0.15)",
            }}
            onClick={prevSlide}
          >
            <BiChevronLeft />
          </IconButton>
        )}
      </Flex>

      <Flex
        sx={{
          gridArea: "footer-right",
          alignItems: "start",
          justifyContent: "end",
          padding: "0em 4em",
        }}
      >
        {!!state.step && (
          <Button
            data-cy="continue"
            onClick={nextSlide}
            title="continue"
            tabIndex={0}
          >
            Continue
          </Button>
        )}
      </Flex>
    </OnboardingGrid>
  );
}