react-toastify#Slide TypeScript Examples

The following examples show how to use react-toastify#Slide. 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: App.tsx    From posthog-foss with MIT License 6 votes vote down vote up
function AppScene(): JSX.Element | null {
    const { user } = useValues(userLogic)
    const { activeScene, params, loadedScenes, sceneConfig } = useValues(sceneLogic)
    const { showingDelayedSpinner } = useValues(appLogic)

    const SceneComponent: (...args: any[]) => JSX.Element | null =
        (activeScene ? loadedScenes[activeScene]?.component : null) ||
        (() => (showingDelayedSpinner ? <SceneLoading /> : null))

    const toastContainer = <ToastContainer autoClose={8000} transition={Slide} position="bottom-right" />

    if (!user) {
        return sceneConfig?.onlyUnauthenticated || sceneConfig?.allowUnauthenticated ? (
            <Layout style={{ minHeight: '100vh' }}>
                <SceneComponent {...params} />
                {toastContainer}
            </Layout>
        ) : null
    }

    return (
        <>
            <Navigation>
                <SceneComponent user={user} {...params} />
            </Navigation>
            {toastContainer}
            <UpgradeModal />
        </>
    )
}
Example #2
Source File: ToolbarApp.tsx    From posthog-foss with MIT License 6 votes vote down vote up
export function ToolbarApp(props: ToolbarProps = {}): JSX.Element {
    const { jsURL } = useValues(toolbarLogic(props))

    const shadowRef = useRef<HTMLElementWithShadowRoot | null>(null)
    const [didLoadStyles, setDidLoadStyles] = useState(false)

    // this runs after the shadow root has been added to the dom
    const didRender = useSecondRender(
        props.disableExternalStyles
            ? () => {}
            : () => {
                  const styleLink = document.createElement('link')
                  styleLink.rel = 'stylesheet'
                  styleLink.type = 'text/css'
                  styleLink.href = `${jsURL}/static/toolbar.css`
                  styleLink.onload = () => setDidLoadStyles(true)
                  const shadowRoot =
                      shadowRef.current?.shadowRoot || window.document.getElementById('__POSTHOG_TOOLBAR__')?.shadowRoot
                  shadowRoot?.getElementById('posthog-toolbar-styles')?.appendChild(styleLink)
              }
    )

    return (
        <>
            <root.div id="__POSTHOG_TOOLBAR__" className="ph-no-capture" ref={shadowRef}>
                <div id="posthog-toolbar-styles" />
                {didRender && (didLoadStyles || props.disableExternalStyles) ? <ToolbarContainer /> : null}
                <ToastContainer autoClose={8000} transition={Slide} position="bottom-center" />
            </root.div>
        </>
    )
}
Example #3
Source File: StateContainer.tsx    From mail-my-ballot with Apache License 2.0 6 votes vote down vote up
UnstatedContainer: React.FC<{}> = ({ children }) => (<HashRouter>
  <AddressContainer.Provider>
    <ContactContainer.Provider>
      <AnalyticsContainer.Provider>
        <FeatureFlagsContainer.Provider>
          <VoterContainer.Provider>
            <ModalProvider>
              <FetchingDataContainer.Provider>
                {children}
                <LoadingOverlay/>
                <CustomToastContainer
                  position="top-right"
                  autoClose={3000}
                  hideProgressBar={true}
                  newestOnTop={true}
                  closeOnClick={true}
                  rtl={false}
                  limit={2}
                  pauseOnFocusLoss={true}
                  pauseOnHover={true}
                  transition={Slide}
                />
              </FetchingDataContainer.Provider>
            </ModalProvider>
          </VoterContainer.Provider>
        </FeatureFlagsContainer.Provider>
      </AnalyticsContainer.Provider>
    </ContactContainer.Provider>
  </AddressContainer.Provider>
</HashRouter>)
Example #4
Source File: index.tsx    From slice-machine with Apache License 2.0 6 votes vote down vote up
ToastContainer: React.FunctionComponent = () => {
  return (
    <ReactToastifyContainer
      autoClose={2500}
      hideProgressBar
      transition={Slide}
      closeButton={false}
      position={toast.POSITION.TOP_CENTER}
      icon={getIconAccordingToasterType}
    />
  );
}
Example #5
Source File: Container.tsx    From houston with MIT License 5 votes vote down vote up
ToastContainer: React.FC<ToastContainerProps> = props => {
  const theme = useHoustonTheme();
  const styleContent = React.useMemo(
    () => ({
      __html: `
        ${styles}

        .Toastify__toast {
          border-radius: 4px;
          margin-bottom: 16px;
          padding: 8px 16px;
        }

        .Toastify__toast-body {
          font-family: ${theme?.font?.family ?? 'Open Sans'};
          font-weight: 600;
          padding-right: 8px;
          line-height: 1.45;
        }

        .Toastify__close-button {
          align-self: center;
        }
      `
    }),
    [theme?.font?.family]
  );

  return (
    <>
      <style dangerouslySetInnerHTML={styleContent} />

      <ToastContainerToastify
        {...props}
        transition={Slide}
        position='top-right'
        autoClose={4000}
        hideProgressBar={false}
        newestOnTop={false}
        closeOnClick
        rtl={false}
        draggable={false}
        pauseOnFocusLoss
        pauseOnHover
        icon={false}
        limit={4}
      />
    </>
  );
}
Example #6
Source File: App.tsx    From foodie with MIT License 5 votes vote down vote up
function App() {
  const [isCheckingSession, setCheckingSession] = useState(true);
  const dispatch = useDispatch();
  const isNotMobile = window.screen.width >= 800;

  useEffect(() => {
    (async () => {
      try {
        const { auth } = await checkAuthSession();

        dispatch(loginSuccess(auth));

        socket.on('connect', () => {
          socket.emit('userConnect', auth.id);
          console.log('Client connected to socket.');
        });

        // Try to reconnect again
        socket.on('error', function () {
          socket.emit('userConnect', auth.id);
        });

        setCheckingSession(false);
      } catch (e) {
        console.log('ERROR', e);
        setCheckingSession(false);
      }
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return isCheckingSession ? (
    <Preloader />
  ) : (
    <Router history={history}>
      <main className="relative min-h-screen">
        <ToastContainer
          position="bottom-left"
          autoClose={5000}
          transition={Slide}
          draggable={false}
          hideProgressBar={true}
          bodyStyle={{ paddingLeft: '15px' }}
        />
        <NavBar />
        <Switch>
          <PublicRoute path={ROUTE.REGISTER} component={pages.Register} />
          <PublicRoute path={ROUTE.LOGIN} component={pages.Login} />
          <ProtectedRoute path={ROUTE.SEARCH} component={pages.Search} />
          <Route path={ROUTE.HOME} exact render={(props: any) => <pages.Home key={Date.now()} {...props} />} />
          <ProtectedRoute path={ROUTE.POST} component={pages.Post} />
          <ProtectedRoute path={ROUTE.PROFILE} component={pages.Profile} />
          <ProtectedRoute path={ROUTE.CHAT} component={pages.Chat} />
          <ProtectedRoute path={ROUTE.SUGGESTED_PEOPLE} component={pages.SuggestedPeople} />
          <Route path={ROUTE.SOCIAL_AUTH_FAILED} component={pages.SocialAuthFailed} />
          <Route component={pages.PageNotFound} />
        </Switch>
        {isNotMobile && <Chats />}
      </main>
    </Router>
  );
}
Example #7
Source File: index.tsx    From payload with MIT License 5 votes vote down vote up
Index = () => (
  <React.Fragment>
    <ConfigProvider config={config}>
      <WindowInfoProvider breakpoints={{
        xs: '(max-width: 400px)',
        s: '(max-width: 768px)',
        m: '(max-width: 1024px)',
        l: '(max-width: 1440px)',
      }}
      >
        <ScrollInfoProvider>
          <Router>
            <ModalProvider
              classPrefix="payload"
              zIndex={50}
            >
              <AuthProvider>
                <PreferencesProvider>
                  <SearchParamsProvider>
                    <LocaleProvider>
                      <StepNavProvider>
                        <CustomProvider>
                          <Routes />
                        </CustomProvider>
                      </StepNavProvider>
                    </LocaleProvider>
                  </SearchParamsProvider>
                  <ModalContainer />
                </PreferencesProvider>
              </AuthProvider>
            </ModalProvider>
          </Router>
        </ScrollInfoProvider>
      </WindowInfoProvider>
    </ConfigProvider>
    <ToastContainer
      position="bottom-center"
      transition={Slide}
      icon={false}
    />
  </React.Fragment>
)
Example #8
Source File: App.tsx    From index-ui with MIT License 4 votes vote down vote up
Providers: React.FC = ({ children }) => {
  const [darkModeSetting] = useLocalStorage('darkMode', true)
  const { dark: darkTheme, light: lightTheme } = useMemo(() => {
    return createTheme()
  }, [])

  return (
    <ThemeProvider
      darkModeEnabled={darkModeSetting}
      darkTheme={darkTheme}
      lightTheme={lightTheme}
    >
      <TransactionWatcherProvider>
        <WalletProvider>
          <DAppProvider config={config}>
            <ChainIdProvider>
              <ApolloProvider client={graphqlClient}>
                <MediaQueryProvider>
                  <BalancesProvider>
                    <FarmingProvider>
                      <FarmingTwoProvider>
                        <MviStakingRewardsProvider>
                          <PricesProvider>
                            <BuySellProvider>
                              <Eth2xFLIPTokenMarketDataProvider>
                                <Eth2xFLIPTokenSupplyCapProvider>
                                  <IEthFLIPTokenMarketDataProvider>
                                    <IEthFLIPTokenSupplyCapProvider>
                                      <Matic2xFLIPTokenMarketDataProvider>
                                        <Matic2xFLIPTokenSupplyCapProvider>
                                          <IMaticFLIPTokenMarketDataProvider>
                                            <IMaticFLIPTokenSupplyCapProvider>
                                              <Eth2xFliTokenMarketDataProvider>
                                                <Eth2xFliTokenSupplyCapProvider>
                                                  <Btc2xFliTokenMarketDataProvider>
                                                    <Btc2xFliTokenSupplyCapProvider>
                                                      <DpiTokenMarketDataProvider>
                                                        <MviTokenMarketDataProvider>
                                                          <BedTokenMarketDataProvider>
                                                            <GmiTokenMarketDataProvider>
                                                              <DataTokenMarketDataProvider>
                                                                <IndexTokenMarketDataProvider>
                                                                  <V3FarmingProvider>
                                                                    <GmiFarmingProvider>
                                                                      <StreamingFeeProvider>
                                                                        <TokenSupplyProvider>
                                                                          <SetComponentsProvider>
                                                                            {
                                                                              children
                                                                            }
                                                                          </SetComponentsProvider>
                                                                        </TokenSupplyProvider>
                                                                      </StreamingFeeProvider>
                                                                    </GmiFarmingProvider>
                                                                  </V3FarmingProvider>
                                                                </IndexTokenMarketDataProvider>
                                                              </DataTokenMarketDataProvider>
                                                            </GmiTokenMarketDataProvider>
                                                          </BedTokenMarketDataProvider>
                                                        </MviTokenMarketDataProvider>
                                                      </DpiTokenMarketDataProvider>
                                                    </Btc2xFliTokenSupplyCapProvider>
                                                  </Btc2xFliTokenMarketDataProvider>
                                                </Eth2xFliTokenSupplyCapProvider>
                                              </Eth2xFliTokenMarketDataProvider>
                                            </IMaticFLIPTokenSupplyCapProvider>
                                          </IMaticFLIPTokenMarketDataProvider>
                                        </Matic2xFLIPTokenSupplyCapProvider>
                                      </Matic2xFLIPTokenMarketDataProvider>
                                    </IEthFLIPTokenSupplyCapProvider>
                                  </IEthFLIPTokenMarketDataProvider>
                                </Eth2xFLIPTokenSupplyCapProvider>
                              </Eth2xFLIPTokenMarketDataProvider>
                            </BuySellProvider>
                          </PricesProvider>
                        </MviStakingRewardsProvider>
                      </FarmingTwoProvider>
                    </FarmingProvider>
                  </BalancesProvider>
                </MediaQueryProvider>
              </ApolloProvider>
            </ChainIdProvider>
          </DAppProvider>
        </WalletProvider>
      </TransactionWatcherProvider>
      <ToastContainer transition={Slide} position='bottom-left' />
    </ThemeProvider>
  )
}
Example #9
Source File: index.tsx    From tweet2image with MIT License 4 votes vote down vote up
export function MainApp({
  GYAZO_CLIENT_ID,
  currentUrl,
}: {
  GYAZO_CLIENT_ID: string
  currentUrl: string
}) {
  const [loading, setLoading] = useState(false)
  const initialFormState = useInitialFormState()
  const [formState, dispatch] = useReducer(formReducer, initialFormState)
  const [blob, setBlob] = useState<string | null>(null)
  const [loaded, setLoaded] = useState(false)
  const [isGyazoUploading, setIsGyazoUploading] = useState(false)
  const [gyazoRedirect, setGyazoRedirect] = useState<string | null>(null)
  const [gyazoSnippet, setGyazoSnippet] = useState<string | null>(null)
  const formRef = useRef<HTMLFormElement>(null)
  const proceededUrl = useRef<string | null>(null)
  const tweetId = useRef<string | null>(null)
  const hash = useRef<string | null>(null)
  const isNowEditing = useRef<boolean>(false)
  const retryCount = useRef<number>(0)
  const { gyazoClientId, userGyazoClientId, setGyazoClientId } =
    useGyazoClientIdState(GYAZO_CLIENT_ID)
  const { editing, addTaskOnEditFinished, handleEditingStateChange } =
    useEditingState()

  const getChangedSetting = () => {
    const settings: { [key: string]: string | number } = {}
    if (formState.lang !== "ja") settings["lang"] = formState.lang
    if (formState.timezone !== 9) settings["tz"] = formState.timezone
    if (formState.theme !== "light") settings["theme"] = formState.theme
    if (formState.scale !== 2) settings["scale"] = formState.scale
    return settings
  }

  const getImageUrl = () => {
    const settings = getChangedSetting()
    const url = new URL(currentUrl)
    url.pathname = `${tweetId.current}.${formState.imageFormat}`
    if (!!Object.keys(settings).length) {
      url.search = querystring.stringify(settings)
    }
    return url.href
  }

  const getScrapboxSnippet = () => {
    return `[${getImageUrl()} ${proceededUrl.current}]`
  }

  const onSubmit = async () => {
    await handleSubmitForm()
  }

  const handleSubmitForm = async () => {
    if (loading) return
    const { url, imageFormat, theme, lang, scale, timezone: tz } = formState
    if (url.length === 0) return
    const m = url.match(/(twitter.com\/(.+)\/status\/)?(\d+)/)
    if (!m) {
      toast.error("The format of the URL is invalid.")
      return
    }

    tweetId.current = m[3]

    const stat = [tweetId.current, imageFormat, theme, lang, scale, tz].join("")
    if (hash.current === stat) return
    hash.current = stat

    proceededUrl.current = `https://twitter.com/${m[2] || "twitter"}/status/${
      tweetId.current
    }`
    setLoading(true)
    setGyazoRedirect(null)

    try {
      const url = new URL(currentUrl)
      url.pathname = `${tweetId.current}.${imageFormat}`
      let imageUrl = url.href
      const settings = getChangedSetting()
      if (!!Object.keys(settings).length) {
        url.search = querystring.stringify(settings)
        imageUrl = url.href
      }
      const r = await fetch(imageUrl)

      if (!r.ok) {
        switch (r.status) {
          case 404:
            toast.error("No tweets found.")
            break
          default:
            toast.error(`An error has occurred: ${r.statusText}`)
            hash.current = null
            setTimeout(async () => {
              if (retryCount.current < 2) {
                retryCount.current++
                if (formRef.current?.requestSubmit) {
                  formRef.current.requestSubmit()
                } else {
                  await handleSubmitForm()
                }
              }
            }, 1000)
            break
        }
        setLoading(false)

        return
      }

      retryCount.current = 0
      const blob = await r.blob()
      const blobUrl = URL.createObjectURL(blob)
      setBlob(blobUrl)

      setLoading(false)
      setLoaded(true)
    } catch (error) {
      toast.error(`An error has occurred.`)
      setLoading(false)
      return
    }
  }

  useEffect(() => {
    let handle: number | undefined
    let remove: (() => void) | undefined
    if (editing) {
      remove = addTaskOnEditFinished(handleSubmitForm)
    } else {
      handle = window.setTimeout(() => handleSubmitForm(), 1000)
    }
    return () => {
      window.clearTimeout(handle)
      remove?.()
    }
  }, [formState, editing, addTaskOnEditFinished])

  useEffect(() => {
    const parsed = new URLSearchParams(location.hash.slice(1))
    if (0 < Array.from(parsed.entries()).length) {
      if (isNowEditing.current || loading) return
      handleSubmitForm()
      /*if (tweetInput.current.form.requestSubmit) {
          setTimeout(() => tweetInput.current.form.requestSubmit(), 0)
        } else {
          handleSubmitForm()
        }*/
    }
  }, [])

  const tweetUploadToGyazo = async () => {
    if (!blob) {
      return
    }
    setIsGyazoUploading(true)
    toast.info("Uploading to Gyazo...")
    try {
      const r = await fetch(blob)
      const imageData = await r.blob()
      const base64Img: Blob = await new Promise((res, rej) => {
        const reader = new FileReader()
        reader.onerror = rej
        reader.onload = () => {
          res(reader.result as any as Blob)
        }
        reader.readAsDataURL(imageData)
      })
      const formData = new FormData()
      formData.append("client_id", gyazoClientId)
      formData.append("referer_url", proceededUrl.current || "")
      formData.append("image_url", base64Img)
      const easyAuth = await fetch(
        `https://upload.gyazo.com/api/upload/easy_auth`,
        {
          method: "POST",
          mode: "cors",
          body: formData,
        }
      )
      const uploadResult = await easyAuth.json()
      window.open(uploadResult.get_image_url, "pop", "width=800, height=480")
      setGyazoRedirect(uploadResult.get_image_url)
      setGyazoSnippet(`[ ${proceededUrl.current}]`)
    } catch (e) {
      console.error(e)
      toast.error("Failed to upload to gyazo")
    } finally {
      setIsGyazoUploading(false)
    }
  }

  return (
    <div className="min-h-screen w-full flex flex-col text-gray-800">
      <ToastContainer
        position={"top-left"}
        autoClose={2500}
        closeOnClick={true}
        transition={Slide}
      />
      <div className="flex-1">
        <div className="container mx-auto max-w-screen-md p-4">
          <div className="m-1 mt-4 mb-2 text-2xl flex justify-between items-center relative">
            <h1>tweet2image</h1>
            <details style={{ fontSize: 0 }}>
              <summary className="text-gray-600 flex items-center">
                <Settings aria-label="設定" size={20} />
              </summary>
              <div className="absolute bg-white shadow mt-8 right-0 top-0 z-20">
                <div className="text-sm p-4 leading-relaxed">
                  <h1 className="text-lg pb-2">設定</h1>
                  <h2 className="text-base pb-2">Gyazo Client ID</h2>
                  <input
                    type="text"
                    placeholder={GYAZO_CLIENT_ID}
                    className="appearance-none block w-full border border-gray-200 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white focus:border-gray-500 bg-gray-100 text-gray-700"
                    value={userGyazoClientId || ""}
                    onChange={(e) => setGyazoClientId(e.target.value)}
                  ></input>
                </div>
              </div>
            </details>
          </div>
          <hr />

          <div className="mx-1">
            <div className="mt-2">
              <Form
                ref={formRef}
                state={formState}
                dispatch={dispatch}
                disabled={loading}
                onEditingStateChange={handleEditingStateChange}
                onSubmit={onSubmit}
              />
            </div>
            <div className="mt-4">
              {loaded && proceededUrl.current ? (
                <a href={proceededUrl.current} target="_blank" rel="noopener">
                  <div className="relative w-full text-center bg-gray-300 rounded-t">
                    {blob && <img className="w-full" src={blob} />}
                    <div className="absolute loading-center">
                      <div className="h-full flex items-center justify-center">
                        <div
                          className={`loading ${
                            loading ? "opacity-100" : "opacity-0"
                          }`}
                        ></div>
                      </div>
                    </div>
                  </div>
                </a>
              ) : (
                <div className="h-full w-full flex-none bg-cover text-center bg-gray-300 rounded-t bg-center placeholder-cover">
                  <div className="flex items-center justify-center">
                    <div
                      className={`loading ${
                        loading ? "opacity-100" : "opacity-0"
                      }`}
                    ></div>
                  </div>
                </div>
              )}
            </div>

            {tweetId.current && (
              <div className="mt-2">
                <label className="block tracking-wide text-gray-600 text-sm mb-2">
                  Image Url
                </label>
                <div className="flex flex-wrap items-stretch w-full mb-4 relative">
                  <input
                    type="text"
                    className="flex-shrink flex-grow leading-normal w-px flex-1 h-10 rounded rounded-r-none px-3 relative bg-gray-200 text-gray-700 border border-gray-200"
                    value={getImageUrl()}
                    readOnly
                  />
                  <div className="flex -mr-px">
                    <button
                      className="flex items-center leading-normal bg-grey-lighter rounded rounded-l-none border border-l-0 border-grey-light px-3 whitespace-no-wrap text-grey-dark text-sm"
                      onClick={async () => {
                        try {
                          if (navigator.clipboard) {
                            await navigator.clipboard.writeText(getImageUrl())
                            toast.info("copied.")
                          }
                        } catch (e) {
                          console.error(e)
                        }
                      }}
                    >
                      Copy
                    </button>
                  </div>
                </div>
                <label className="block tracking-wide text-gray-600 text-sm mb-2">
                  Scrapbox Snippet
                </label>
                <div className="flex flex-wrap items-stretch w-full mb-4 relative">
                  <input
                    type="text"
                    className="flex-shrink flex-grow leading-normal w-px flex-1 h-10 rounded rounded-r-none px-3 relative bg-gray-200 text-gray-700 border border-gray-200"
                    value={getScrapboxSnippet()}
                    readOnly
                  />
                  <div className="flex -mr-px">
                    <button
                      className="flex items-center leading-normal bg-grey-lighter rounded rounded-l-none border border-l-0 border-grey-light px-3 whitespace-no-wrap text-grey-dark text-sm"
                      onClick={async () => {
                        try {
                          if (navigator.clipboard) {
                            await navigator.clipboard.writeText(
                              getScrapboxSnippet()
                            )
                            toast.info("copied.")
                          }
                        } catch (e) {
                          console.error(e)
                        }
                      }}
                    >
                      Copy
                    </button>
                  </div>
                </div>
                <div className="mx-auto mt-6 mb-2">
                  <button
                    className={`flex items-center leading-normal bg-gray-lighter rounded border border-indigo-200 p-2 whitespace-no-wrap text-grey-dark text-sm mx-auto ${
                      (loading ||
                        isGyazoUploading ||
                        !!gyazoRedirect ||
                        !gyazoClientId) &&
                      "bg-gray-200 text-gray-400"
                    }`}
                    disabled={
                      loading ||
                      isGyazoUploading ||
                      !!gyazoRedirect ||
                      !gyazoClientId
                    }
                    onClick={tweetUploadToGyazo}
                  >
                    Upload to Gyazo?
                  </button>
                  {gyazoRedirect && (
                    <div>
                      <label className="block tracking-wide text-gray-600 text-sm my-2">
                        Scrapbox Snippet
                      </label>
                      <div className="flex flex-wrap items-stretch w-full mb-1 relative">
                        <input
                          type="text"
                          className="flex-shrink flex-grow leading-normal w-px flex-1 h-10 rounded rounded-r-none px-3 relative bg-gray-100 text-gray-700 border border-gray-200"
                          value={gyazoSnippet || ""}
                          onChange={(e) => setGyazoSnippet(e.target.value)}
                        />
                        <div className="flex -mr-px">
                          <button
                            className="flex items-center leading-normal bg-grey-lighter rounded rounded-l-none border border-l-0 border-grey-light px-3 whitespace-no-wrap text-grey-dark text-sm"
                            onClick={async () => {
                              try {
                                if (navigator.clipboard && gyazoSnippet) {
                                  await navigator.clipboard.writeText(
                                    gyazoSnippet
                                  )
                                  toast.info("copied.")
                                }
                              } catch (e) {
                                console.error(e)
                              }
                            }}
                          >
                            Copy
                          </button>
                        </div>
                      </div>
                      <p className="text-sm text-gray-600">
                        To complete this snippet, paste{" "}
                        <a
                          className="text-blue-400"
                          href={gyazoRedirect}
                          target="_blank"
                        >
                          the URL of the Gyazo page
                        </a>{" "}
                        opened on the popup to in the text box above.
                      </p>
                    </div>
                  )}
                </div>
              </div>
            )}
          </div>
        </div>
      </div>

      <div className="container max-w-screen-md mx-auto">
        <hr />
        <div className="flex justify-end text-xs p-4">
          <div className="text-right">
            <span>
              tweet2image&nbsp;/&nbsp;
              <a
                className="text-blue-400"
                target="_blank"
                href="https://github.com/ci7lus/tweet2image"
                rel="noopener"
              >
                code &amp; bug report
              </a>
              &nbsp;/&nbsp;
            </span>
            <span className="inline-block">
              Animation from&nbsp;
              <a
                className="text-blue-400"
                href="https://github.com/potato4d/preloaders"
                target="_blank"
                rel="noopener"
              >
                potato4d/preloaders
              </a>
            </span>
          </div>
        </div>
      </div>
    </div>
  )
}