react-hot-toast#Toaster TypeScript Examples

The following examples show how to use react-hot-toast#Toaster. 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: ToastManager.tsx    From querybook with Apache License 2.0 6 votes vote down vote up
ToastManager: React.FC = () => (
    <Toaster
        position="bottom-right"
        reverseOrder={false}
        toastOptions={{
            // Define default options
            style: {
                padding: '12px',
                marginBottom: '12px',
                backgroundColor: 'var(--bg-light)',
                color: 'var(--text-dark)',
                zIndex: 301,
                borderRadius: 'var(--border-radius)',
            },
            success: {
                duration: 3000,
            },
        }}
    />
)
Example #2
Source File: index.tsx    From mysterium-vpn-desktop with MIT License 6 votes vote down vote up
App: React.FC = () => (
    <React.Fragment>
        <GlobalStyle />
        <HistoryRouter history={history}>
            <StoreContext.Provider value={rootStore}>
                <Routes />
            </StoreContext.Provider>
        </HistoryRouter>
        <Toaster
            position="top-right"
            gutter={40}
            containerStyle={{
                marginTop: 35,
                overflowWrap: "anywhere",
                wordBreak: "break-word",
                fontSize: 14,
            }}
            toastOptions={{
                duration: 8_000,
            }}
        />
    </React.Fragment>
)
Example #3
Source File: layout.tsx    From admin with MIT License 6 votes vote down vote up
Layout: React.FC = ({ children }) => {
  return (
    <div className="flex w-full h-screen inter-base-regular text-grey-90">
      <Toaster
        containerStyle={{
          top: 74,
          left: 24,
          bottom: 24,
          right: 24,
        }}
      />
      <Sidebar />
      <div className="flex flex-col flex-1">
        <Topbar />
        <div className="large:px-xlarge py-xlarge bg-grey-5 min-h-content overflow-y-auto">
          <main className="xsmall:mx-base small:mx-xlarge medium:mx-4xlarge large:mx-auto large:max-w-7xl large:w-full h-full">
            {children}
          </main>
        </div>
      </div>
    </div>
  )
}
Example #4
Source File: _app.tsx    From react-celo with MIT License 6 votes vote down vote up
function MyApp({ Component, pageProps, router }: AppProps): React.ReactElement {
  if (router.route !== '/') {
    return (
      <div className="max-w-screen-sm mx-auto py-10 md:py-20 px-4">
        <Component {...pageProps} />
      </div>
    );
  }

  return (
    <CeloProvider
      dapp={{
        name: 'react-celo demo',
        description: 'A demo DApp to showcase functionality',
        url: 'https://react-celo.vercel.app',
        icon: 'https://react-celo.vercel.app/favicon.ico',
      }}
      network={Alfajores}
      connectModal={{
        providersOptions: { searchable: true },
      }}
    >
      <Toaster
        position="top-right"
        toastOptions={{
          className: 'w-72 md:w-96',
          style: {
            padding: '0px',
          },
        }}
      />
      <div className="max-w-screen-sm mx-auto py-10 md:py-20 px-4">
        <Component {...pageProps} />
      </div>
    </CeloProvider>
  );
}
Example #5
Source File: RoomCode.tsx    From NextLevelWeek with MIT License 6 votes vote down vote up
export function RoomCode(props: RoomCodeProps) {
  // Função de copar o código da sala.
  function copyRoomCodeToClipboard() {
    toast.success("Código da sala copiado com sucesso!", {
      id: props.code,
      style: {
        width: "40rem",
      },
    });

    navigator.clipboard.writeText(props.code);
  }

  return (
    <>
      <Toaster position="top-right" reverseOrder={false} />
      <button className="room-code" onClick={copyRoomCodeToClipboard}>
        <div>
          <img src={copyImg} alt="Copy room code" />
        </div>
        <span>Sala #{props.code}</span>
      </button>
    </>
  );
}
Example #6
Source File: App.tsx    From personal-archive with MIT License 5 votes vote down vote up
App = () => (
  <>
    <BrowserRouter>
      <ScrollToTop />
      <div>
        <Switch>
          <Route path="/articles/new">
            <CreateArticlePage/>
          </Route>
          <Route path="/articles/search">
            <SearchPage/>
          </Route>
          <Route path="/articles/:id/edit">
            <EditArticlePage/>
          </Route>
          <Route path="/articles/:id">
            <ArticlePage/>
          </Route>
          <Route path="/tags/:tag">
            <ArticlesByTagPage/>
          </Route>

          <Route path="/notes/:id/paragraphs/:paragraphID">
            <EditNoteParagraphPage/>
          </Route>
          <Route path="/notes/:id/paragraphs">
            <NewNoteParagraphPage/>
          </Route>
          <Route path="/notes/new">
            <NewNotePage/>
          </Route>
          <Route path="/notes/:id">
            <NotePage/>
          </Route>
          <Route path="/notes">
            <NoteListPage/>
          </Route>

          <Route path="/settings/pocket-auth">
            <PocketAuthPage/>
          </Route>
          <Route path="/settings">
            <SettingPage/>
          </Route>
          <Route path="/">
            <Redirect to="/tags/all"/>
          </Route>
        </Switch>
      </div>
      <GlobalConfirm />
      <GlobalPrompt />
    </BrowserRouter>
    <Toaster position="top-right"/>
  </>
)
Example #7
Source File: _app.tsx    From basement-grotesque with SIL Open Font License 1.1 5 votes vote down vote up
App = ({ Component, pageProps }: AppProps) => {
  const [fontsLoaded, setFontsLoaded] = useState(false)

  useAppGA()

  useEffect(() => {
    // @ts-ignore
    document.fonts.ready
      .then(() => {
        setFontsLoaded(true)
      })
      .catch((error: unknown) => {
        console.error(error)
        setFontsLoaded(true)
      })
  }, [])

  useEffect(() => {
    if (!fontsLoaded) return

    try {
      const title = new SplitText('.hero__title', {
        type: 'chars'
      })

      const subtitle = new SplitText('.hero__subtitle', {
        type: 'chars'
      })

      const timeline = gsap.timeline({
        paused: true,
        smoothChildTiming: true
      })

      timeline.to('body', {
        autoAlpha: 1,
        duration: DURATION / 2
      })
      timeline.in(title.chars, '<80%')
      timeline.in(subtitle.chars, '<40%')
      timeline.from(
        ['.hero__link', '.hero__image'],
        {
          autoAlpha: 0,
          duration: DURATION * 0.8,
          stagger: 0.15,
          yPercent: 60
        },
        '>-20%'
      )

      timeline.timeScale(1.4).play()

      return () => {
        timeline?.kill()
      }
    } catch (error) {
      document.body.style.opacity = '1'
    }
  }, [fontsLoaded])

  return (
    <QueryClientProvider client={queryClient}>
      <Context.Provider value={{ fontsLoaded }}>
        <Toaster position="bottom-center" />
        <Cursor>
          <LocomotiveScrollProvider>
            <Header />
            <Component {...pageProps} />
          </LocomotiveScrollProvider>
        </Cursor>
      </Context.Provider>
    </QueryClientProvider>
  )
}
Example #8
Source File: NewRoom.tsx    From NextLevelWeek with MIT License 5 votes vote down vote up
export function NewRoom() {
  // Tendo acesso ao usuário autenticado.
  const { user } = useAuth();

  const history = useHistory();

  const [newRoom, setNewRoom] = useState("");

  // Função de criação de uma sala.
  async function handleCreateRoom(event: FormEvent) {
    // Prevenindo o comportamento padrão do formulário.
    event.preventDefault();

    // Tendo acesso ao valor do input.
    // console.log(newRoom);
    if (newRoom.trim() === "") {
      toast.error("Room name cannot be empty.", {
        icon: "⚠️",
      });
      return;
    }

    const roomRef = database.ref("rooms");
    // "jogando" uma informação dentro de "rooms"
    const firebaseRoom = await roomRef.push({
      title: newRoom,
      authorId: user?.id,
    });

    // Após o usuário crar a sala, ele será redirecionado para a nova sala criada.
    history.push(`/rooms/${firebaseRoom.key}`);
  }

  return (
    <div id="page-auth">
      <Toaster position="top-right" reverseOrder={false} />
      <aside>
        <img
          src={illustrationImg}
          alt="Ilustração simbolizando perguntas e respostas."
        />
        <strong>Crie salas de Q&amp;E ao-vivo.</strong>
        <p>Tire as dúvidas da sua audência em tempo-real.</p>
      </aside>
      <main>
        <div className="main-content">
          <img src={logoImg} alt="Letmeask" />

          <h2>Criar uma nova sala</h2>
          <form onSubmit={handleCreateRoom}>
            <input
              type="text"
              placeholder="Nome da sala"
              onChange={(event) => setNewRoom(event.target.value)}
              value={newRoom}
            />
            <Button type="submit">Criar sala</Button>
          </form>
          <p>
            Quer entrar em uma sala existente ? <Link to="/">clique aqui</Link>
          </p>
        </div>
      </main>
    </div>
  );
}
Example #9
Source File: [id].tsx    From globe-3d with MIT License 4 votes vote down vote up
ShareScreen = () => {
  const router = useRouter();
  const { id } = router.query;
  const [imageUrl, setImageUrl] = React.useState(null);
  const globeRef: any = React.useRef(null);
  const inputRef: any = React.useRef(null);
  const linkRef: any = React.useRef(null);
  const arcsData = [1, 2, 3, 4, 5, 6].map(() => ({
    startLat: (Math.random() - 0.5) * 180,
    startLng: (Math.random() - 0.5) * 360,
    endLat: (Math.random() - 0.5) * 180,
    endLng: (Math.random() - 0.5) * 360,
    color: [["#000000"][0], ["#000000"][0]],
  }));

  React.useEffect(() => {
    if (id) {
      setImageUrl(`/api/download?id=${id}`);
    }
  }, [id]);

  const processFile = (files) => {
    const data = URL.createObjectURL(files[0]);
    setImageUrl(data);
  };

  const onDrop = React.useCallback((files) => {
    processFile(files);
  }, []);
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

  return (
    <div className="">
      <Head>
        <title>Globe 3D</title>
      </Head>

      <main className="" {...getRootProps()}>
        <div className="relative bg-white overflow-hidden min-h-screen">
          <nav className="bg-white">
            <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
              <div className="border-b border-gray-100">
                <div className="flex items-center justify-between h-16 px-4 sm:px-0">
                  <div className="flex items-center">
                    <div className="flex-shrink-0 text-gray-900">
                      <a href="/">
                        <img
                          className="h-8 w-8"
                          src="/images/logoglobe.png"
                          alt="Globe 3D"
                        />
                      </a>
                    </div>
                    <div className="hidden md:flex flex-1">
                      <div className="ml-10 flex items-baseline space-x-4 justify-end items-end">
                        <a
                          href="https://figma.com/@sonny"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          All Plugins
                        </a>
                        <a
                          href="https://twitter.com/sonnylazuardi"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          Twitter
                        </a>
                        <a
                          href="https://github.com/sonnylazuardi/globe-3d"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          Github
                        </a>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </nav>
          <div className="w-96 mx-auto flex flex-col items-center justify-center">
            <div className="">
              <Globe
                //@ts-ignore
                ref={globeRef}
                width={480}
                height={480}
                backgroundColor={"rgba(0,0,0,0)"}
                globeImageUrl={imageUrl}
                arcColor={"color"}
                arcsData={arcsData}
                arcDashGap={0.6}
                arcDashLength={0.3}
                arcDashAnimateTime={4000 + 500}
                rendererConfig={{ preserveDrawingBuffer: true }}
              />
              <a className="hidden" ref={linkRef} />
            </div>
            <div className="py-10 px-10 rounded-xl bg-white border border-gray-100 shadow-xl bg-opacity-25 flex flex-col mb-12">
              <button
                onClick={() => {
                  inputRef?.current.click();
                }}
                type="button"
                className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white mb-2"
              >
                <input
                  ref={inputRef}
                  onChange={(e) => processFile(e.target.files)}
                  type="file"
                  className="hidden"
                />
                <CloudUploadIcon className="h-5 w-5 text-blue-500 mr-2" />
                Upload Image
              </button>
              <button
                onClick={() => {
                  // console.log(globeRef.current);

                  const canvas = globeRef.current.renderer().domElement;
                  const link = linkRef.current;
                  link.setAttribute("download", "globe.png");
                  link.setAttribute(
                    "href",
                    canvas
                      .toDataURL("image/png")
                      .replace("image/png", "image/octet-stream")
                  );
                  link.click();
                }}
                type="button"
                className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white mb-2"
              >
                <CloudDownloadIcon className="h-5 w-5 text-blue-500 mr-2" />
                Download Image
              </button>
              <button
                onClick={() => {
                  const dummy = document.createElement("input"),
                    text = window.location.href;

                  document.body.appendChild(dummy);
                  dummy.value = text;
                  dummy.select();
                  document.execCommand("copy");
                  document.body.removeChild(dummy);
                  toast.success("Copied Globe Share URL");
                }}
                type="button"
                className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white"
              >
                <ClipboardCopyIcon className="h-5 w-5 text-blue-500 mr-2" />
                Copy Share Url
              </button>
            </div>
          </div>
          <footer className="bg-gradient-to-r from-blue-300 to-blue-500">
            <div className="max-w-7xl mx-auto py-12 px-4 overflow-hidden sm:px-6 lg:px-8">
              <nav
                className="-mx-5 -my-2 flex flex-wrap justify-center"
                aria-label="Footer"
              >
                <div className="px-5 py-2">
                  <a
                    href="/"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Home
                  </a>
                </div>
                <div className="px-5 py-2">
                  <a
                    href="https://twitter.com/sonnylazuardi"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Twitter
                  </a>
                </div>
                <div className="px-5 py-2">
                  <a
                    href="https://github.com/sonnylazuardi/globe-3d"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Github
                  </a>
                </div>
              </nav>
              <p className="mt-8 text-center text-base text-white">
                © 2021 Sonny Lazuardi. All rights reserved.
              </p>
            </div>
          </footer>
        </div>
        {isDragActive ? (
          <div className="fixed top-0 left-0 right-0 bottom-0 bg-black bg-opacity-50 flex justify-center items-center ">
            <p className="text-3xl text-white text-center font-bold">
              Drop the file here ...
            </p>
          </div>
        ) : null}
      </main>

      <footer className=""></footer>
      <Toaster />
    </div>
  );
}
Example #10
Source File: index.tsx    From globe-3d with MIT License 4 votes vote down vote up
Home = () => {
  const [globeFile, setGlobeFile] = React.useState(null);
  const router = useRouter();
  const [imageUrl, setImageUrl] = React.useState("/images/texture.png");
  const globeRef: any = React.useRef(null);
  const inputRef: any = React.useRef(null);
  const linkRef: any = React.useRef(null);
  const arcsData = [1, 2, 3, 4, 5, 6].map(() => ({
    startLat: (Math.random() - 0.5) * 180,
    startLng: (Math.random() - 0.5) * 360,
    endLat: (Math.random() - 0.5) * 180,
    endLng: (Math.random() - 0.5) * 360,
    color: [["#000000"][0], ["#000000"][0]],
  }));

  const processFile = (files) => {
    const data = URL.createObjectURL(files[0]);
    setImageUrl(data);
    setGlobeFile(files[0]);
  };

  const onDrop = React.useCallback((files) => {
    processFile(files);
  }, []);
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

  return (
    <div className="">
      <Head>
        <title>Globe 3D</title>
      </Head>

      <main className="" {...getRootProps()}>
        <div className="relative bg-white overflow-hidden min-h-screen">
          <nav className="bg-white">
            <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
              <div className="border-b border-gray-100">
                <div className="flex items-center justify-between h-16 px-4 sm:px-0">
                  <div className="flex items-center">
                    <div className="flex-shrink-0 text-gray-900">
                      <a href="/">
                        <img
                          className="h-8 w-8"
                          src="/images/logoglobe.png"
                          alt="Globe 3D"
                        />
                      </a>
                    </div>
                    <div className="hidden md:flex flex-1">
                      <div className="ml-10 flex items-baseline space-x-4 justify-end items-end">
                        <a
                          href="https://figma.com/@sonny"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          All Plugins
                        </a>
                        <a
                          href="https://twitter.com/sonnylazuardi"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          Twitter
                        </a>
                        <a
                          href="https://github.com/sonnylazuardi/globe-3d"
                          className="text-gray-900 hover:bg-blue-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
                        >
                          Github
                        </a>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </nav>
          <main className="mt-16 pb-16">
            <div className="mx-auto max-w-7xl">
              <div className="lg:grid lg:grid-cols-12 lg:gap-8">
                <div className="px-4 sm:px-6 sm:text-center md:max-w-2xl md:mx-auto lg:col-span-7 lg:text-left lg:flex lg:items-center">
                  <div>
                    <h1 className="mt-4 text-4xl tracking-tight font-extrabold text-black sm:mt-5 sm:leading-none lg:mt-6 lg:text-5xl xl:text-6xl">
                      <span className="md:block">Convert your design to</span>{" "}
                      <span className="font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-pink-500 md:block">
                        3D Globe
                      </span>
                    </h1>
                    <p className="mt-3 text-base text-gray-900 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
                      Create an Interactive 3D globe based on your flat world
                      map design. Try the figma plugin or upload an image to see
                      it live in action.
                    </p>
                    <p className="mt-8 text-sm text-white uppercase tracking-wide font-semibold sm:mt-10 lg:justify-start md:justify-center flex flex-wrap">
                      <a
                        href="https://www.figma.com/community/plugin/977567760148608604/Globe-3D"
                        className="mr-5 inline-flex items-center px-6 py-3 border bg-gradient-to-r from-blue-300 to-blue-500 hover:from-pink-500 hover:to-orange-500 text-white font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105"
                      >
                        <CloudDownloadIcon className="h-5 w-5 text-white mr-2" />
                        Figma Plugin
                      </a>
                      <a
                        href="https://github.com/sonnylazuardi/globe-3d"
                        className="mr-5 inline-flex items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105"
                      >
                        <CodeIcon className="h-5 w-5 text-blue-500 mr-2" />
                        Github
                      </a>
                    </p>
                    <div className="py-6">
                      <p className="text-xs cursor-pointer hover:underline leading-5 text-gray-500">
                        This project is free and open source and built for fun.
                      </p>
                      <p className="text-xs leading-5 text-gray-500">
                        Support the creator by giving star on github and a
                        follow on twitter.
                      </p>
                    </div>
                  </div>
                </div>
                <div className="mt-16 sm:mt-24 lg:mt-0 lg:col-span-5 mx-auto px-5 relative">
                  <div className="absolute left-0 top-72 flex z-50">
                    <div className="py-8 px-8 rounded-xl bg-white border border-gray-100 shadow-xl bg-opacity-25 flex flex-col">
                      <button
                        onClick={() => {
                          inputRef?.current.click();
                        }}
                        type="button"
                        className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white mb-2"
                      >
                        <input
                          ref={inputRef}
                          onChange={(e) => processFile(e.target.files)}
                          type="file"
                          className="hidden"
                        />
                        <CloudUploadIcon className="h-5 w-5 text-blue-500 mr-2" />
                        Upload or Drag & Drop Image
                      </button>

                      {globeFile ? (
                        <>
                          <button
                            onClick={() => {
                              const canvas =
                                globeRef.current.renderer().domElement;
                              const link = linkRef.current;
                              link.setAttribute("download", "globe.png");
                              link.setAttribute(
                                "href",
                                canvas
                                  .toDataURL("image/png")
                                  .replace("image/png", "image/octet-stream")
                              );
                              link.click();
                            }}
                            type="button"
                            className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white mb-2"
                          >
                            <CloudDownloadIcon className="h-5 w-5 text-blue-500 mr-2" />
                            Download Image
                          </button>
                          <button
                            onClick={async () => {
                              if (globeFile) {
                                const id = makeid(8);
                                const toastId = toast.loading(
                                  "Creating your globe URL"
                                );
                                const { data, error } = await supabase.storage
                                  .from("globe")
                                  .upload(`public/${id}.png`, globeFile);
                                if (!error) {
                                  console.log({ data });
                                  toast.success("Your globe URL is Ready", {
                                    id: toastId,
                                  });
                                  router.push(`share/${id}`);
                                }
                              }
                            }}
                            type="button"
                            className="inline-flex justify-center items-center px-6 py-3 border text-blue-500 font-semibold rounded-md transition dutation-150 ease-in-out transform hover:scale-105 bg-white mb-2"
                          >
                            <ShareIcon className="h-5 w-5 text-blue-500 mr-2" />
                            Share Globe
                          </button>
                        </>
                      ) : null}
                    </div>
                  </div>
                  <Globe
                    //@ts-ignore
                    ref={globeRef}
                    width={480}
                    height={480}
                    backgroundColor={"rgba(0,0,0,0)"}
                    globeImageUrl={imageUrl}
                    arcColor={"color"}
                    arcsData={arcsData}
                    arcDashGap={0.6}
                    arcDashLength={0.3}
                    arcDashAnimateTime={4000 + 500}
                    rendererConfig={{ preserveDrawingBuffer: true }}
                  />
                  <a className="hidden" ref={linkRef} />
                </div>
              </div>
            </div>
            <div className="mt-24">
              <h2 className="text-gray-700 text-center text-3xl font-bold">
                Quick Figma Plugin Demo
              </h2>
              <div className="pt-10">
                <div
                  style={{ width: 580, maxWidth: "100%" }}
                  className="mx-auto p-4"
                >
                  <TweetEmbed
                    id="1395404831116849160"
                    options={{
                      theme: "light",
                      conversation: "none",
                      width: 580,
                    }}
                  />
                </div>
              </div>
            </div>
            <div className="mt-24">
              <h2 className="text-gray-700 text-center text-3xl font-bold">
                How is it possible?
              </h2>
              <div className="p-4 text-center">
                This project is powered by React Globe GL
              </div>
              <div className="">
                <div
                  style={{ width: 580, maxWidth: "100%" }}
                  className="mx-auto p-4"
                >
                  <TweetEmbed
                    id="1396007498134417410"
                    options={{
                      theme: "light",
                      conversation: "none",
                      width: 580,
                    }}
                  />
                </div>
              </div>
            </div>
          </main>
          <footer className="bg-gradient-to-r from-blue-300 to-blue-500">
            <div className="max-w-7xl mx-auto py-12 px-4 overflow-hidden sm:px-6 lg:px-8">
              <nav
                className="-mx-5 -my-2 flex flex-wrap justify-center"
                aria-label="Footer"
              >
                <div className="px-5 py-2">
                  <a
                    href="/"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Home
                  </a>
                </div>
                <div className="px-5 py-2">
                  <a
                    href="https://twitter.com/sonnylazuardi"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Twitter
                  </a>
                </div>
                <div className="px-5 py-2">
                  <a
                    href="https://github.com/sonnylazuardi/globe-3d"
                    className="text-base text-gray-200 hover:text-gray-100"
                  >
                    Github
                  </a>
                </div>
              </nav>
              <p className="mt-8 text-center text-base text-white">
                © 2021 Sonny Lazuardi. All rights reserved.
              </p>
            </div>
          </footer>
        </div>
        {isDragActive ? (
          <div className="fixed top-0 left-0 right-0 bottom-0 bg-black bg-opacity-50 flex justify-center items-center ">
            <p className="text-3xl text-white text-center font-bold">
              Drop the file here ...
            </p>
          </div>
        ) : null}
      </main>

      <footer className=""></footer>
      <Toaster />
    </div>
  );
}
Example #11
Source File: LoadingWrapper.tsx    From videotranscode.space with Apache License 2.0 4 votes vote down vote up
LoadingWrapper = ({
  Component,
  children
}: {
  children?: React.ReactNode
  Component?: () => JSX.Element
}) => {
  const {
    processed,
    loaded,
    isLoadingError,
    loadingErrorObj,
    updateLoaded,
    updateLoadError,
    // Stores
    CluiStore,
    VideoStore,
    FileStore
  } = ComponentStore

  const { toDisplay, updateVideoDisplay } = VideoStore

  const { isDisplayable } = FileStore

  const { isSubmitted } = CluiStore

  const [isLoading, setLoading] = useState(false)

  const [secondLoad, setSecondLoad] = useState(false)

  useEffect(() => {
    if (process.browser) {
      if (isLoading === false) {
        setLoading(true)
        setTimeout(() => {
          /**
           * Does not need to load ffmpeg if it is electron app
           */
          electronWrapper(loadFFmpeg, () => {
            updateLoaded(true)
          })
        }, 500)
      }
    } else {
      setLoading(true)
    }
    // eslint-disable-next-line
  }, [])

  useEffect(() => {
    if (isSubmitted) {
      processor()
    }
  }, [isSubmitted])

  useEffect(() => {
    if (loaded) {
      const { updateTerminalText } = TerminalStore

      /**
       * Overriding Console for Terminal
       *
       */
      const newConsole = (oldConsole: typeof window.console) => ({
        ...oldConsole,
        log(text: any) {
          oldConsole.log(`Escaped - ${text}`)
          if (updateTerminalText) {
            updateTerminalText(text)
          }
        }
      })

      window.console = newConsole(window.console)
    }
  }, [loaded])

  useEffect(() => {
    if (process.browser) {
      if (isLoadingError && secondLoad === false) {
        loadFFmpeg()
        setSecondLoad(true)
        updateLoadError(false, new Error())
      }
    }
    // eslint-disable-next-line
  }, [isLoadingError])

  useEffect(() => {
    if (processed) {
      if (!toDisplay) {
        updateVideoDisplay(isDisplayable)
      }
    }
  }, [processed, toDisplay, isDisplayable, updateVideoDisplay])

  if (isLoadingError && secondLoad) {
    return (
      <>
        <div className={appStyles.main}>
          <ErrorScreen errorObj={loadingErrorObj} />
        </div>
        <Footer />
      </>
    )
  }
  if (Component) {
    return <Component></Component>
  }
  if (children) {
    return (
      <>
        <Toaster position="top-right" />

        {children}
      </>
    )
  }
  return null
}
Example #12
Source File: Room.tsx    From NextLevelWeek with MIT License 4 votes vote down vote up
export function Room() {
  // Apenas usuários autenticados podem enviar novas perguntas.
  const { user } = useAuth();

  // "Pegando" o código da sala através dos parâmetros.
  const params = useParams<RoomParams>();
  const roomId = params.id;

  // Importando o Hook useRoom.
  const { questions, title } = useRoom(roomId);

  // Informação da nova pergunta.
  const [newQuestion, setNewQuestion] = useState("");

  // Função para a criação de uma nova pergunta.
  async function handleSendQuestion(event: FormEvent) {
    event.preventDefault();

    if (newQuestion.trim() === "") {
      toast.error("You cannot submit an empty question.", {
        icon: "⚠️",
      });
      return;
    }

    // Se não existir nem um usuário, retornar um erro.
    // Dica de Toast: https://react-hot-toast.com/
    if (!user) {
      throw new Error("You must be logged in.");
    }

    // Criando a pergunta em si.
    const question = {
      content: newQuestion,
      author: {
        name: user.name,
        avatar: user.avatar,
      },
      // Se ela está com "Highlighte" o destaque que o Admin dá na pergunta.
      isHighlighted: false,
      // Se já foi respondida ou não.
      isAnswered: false,
    };

    await database.ref(`rooms/${roomId}/questions`).push(question);

    // "Apagando" a pergunta no textarea após ela ser enviada.
    setNewQuestion("");
  }

  // Função do "like".
  async function handleLikeQuestion(
    questionId: string,
    likeId: string | undefined
  ) {
    if (likeId) {
      // Remover o "like".
      await database
        .ref(`rooms/${roomId}/questions/${questionId}/likes/${likeId}`)
        .remove();
    } else {
      // Adicionando o "like".
      await database.ref(`rooms/${roomId}/questions/${questionId}/likes`).push({
        authorId: user?.id,
      });
    }
  }

  return (
    <div id="page-room">
      <Toaster position="top-right" reverseOrder={false} />
      <header>
        <div className="content">
          <img src={logoImg} alt="Letmeask" />
          <RoomCode code={roomId} />
        </div>
      </header>

      <main>
        <div className="room-title">
          <h1>Sala {title}</h1>
          {questions.length > 0 && <span>{questions.length} pergunta(s)</span>}
        </div>

        <form onSubmit={handleSendQuestion}>
          <textarea
            placeholder="O que deseja perguntar ?"
            onChange={(event) => setNewQuestion(event.target.value)}
            value={newQuestion}
          />
          <div className="form-footer">
            {user ? (
              <div className="user-info">
                <img src={user.avatar} alt={user.name} />
                <span>{user.name}</span>
              </div>
            ) : (
              <span>
                Para enviar uma pergunta, <button>faça seu login</button>.
              </span>
            )}
            <Button type="submit" disabled={!user}>
              Enviar pergunta
            </Button>
          </div>
        </form>

        {/* {JSON.stringify(questions)} */}
        <div className="question-list">
          {questions.map((question) => {
            return (
              <Question
                key={question.id}
                content={question.content}
                author={question.author}
                isAnswered={question.isAnswered}
                isHighlighted={question.isHighlighted}
              >
                {!question.isAnswered && (
                  <button
                    className={`like-button ${question.likeId ? "liked" : ""}`}
                    type="button"
                    aria-label="Marcar como gostei"
                    onClick={() => {
                      handleLikeQuestion(question.id, question.likeId);
                    }}
                  >
                    {question.likeCount > 0 && (
                      <span>{question.likeCount}</span>
                    )}
                    <svg
                      width="24"
                      height="24"
                      viewBox="0 0 24 24"
                      fill="none"
                      xmlns="http://www.w3.org/2000/svg"
                    >
                      <path
                        d="M7 22H4C3.46957 22 2.96086 21.7893 2.58579 21.4142C2.21071 21.0391 2 20.5304 2 20V13C2 12.4696 2.21071 11.9609 2.58579 11.5858C2.96086 11.2107 3.46957 11 4 11H7M14 9V5C14 4.20435 13.6839 3.44129 13.1213 2.87868C12.5587 2.31607 11.7956 2 11 2L7 11V22H18.28C18.7623 22.0055 19.2304 21.8364 19.5979 21.524C19.9654 21.2116 20.2077 20.7769 20.28 20.3L21.66 11.3C21.7035 11.0134 21.6842 10.7207 21.6033 10.4423C21.5225 10.1638 21.3821 9.90629 21.1919 9.68751C21.0016 9.46873 20.7661 9.29393 20.5016 9.17522C20.2371 9.0565 19.9499 8.99672 19.66 9H14Z"
                        stroke="#737380"
                        strokeWidth="1.5"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                      />
                    </svg>
                  </button>
                )}
              </Question>
            );
          })}
        </div>
      </main>
    </div>
  );
}
Example #13
Source File: Home.tsx    From NextLevelWeek with MIT License 4 votes vote down vote up
export function Home() {
  const history = useHistory();
  const { user, signInWithGoogle } = useAuth();

  // Estado para armazenar o código da sala.
  const [roomCode, setRoomCode] = useState("");

  // Navegando para a página de criação de uma sala.
  async function handleCreateRoom() {
    // Se o usuário NÃO estiver autenticado.
    if (!user) {
      await signInWithGoogle();
    }

    // Se já estiver autenticado, redireciona.
    history.push("/rooms/new");
  }

  // Função para entrar em uma sala existente.
  async function handleJoinRoom(event: FormEvent) {
    event.preventDefault();

    // Se retornar vazio, nada irá acontecer.
    if (roomCode.trim() === "") {
      toast.error("Enter a valid room code.", {
        icon: "⚠️",
      });
      return;
    }

    // Verificando se a sala que o usuário está tentando entrar realmente existe.
    const roomRef = await database.ref(`rooms/${roomCode}`).get();

    // Caso retorne falso.
    if (!roomRef.exists()) {
      // alert("Room does not exists.");
      toast.error("Room does not exists.", {
        icon: "⚠️",
      });
      return;
    }

    // Verificando se a sala já não está encerrada.
    if (roomRef.val().endedAt) {
      // alert("Room already closed.");
      toast.error("Room already closed.", {
        icon: "⚠️",
      });
      return;
    }

    // Caso verdadeiro.
    history.push(`/rooms/${roomCode}`);
  }

  return (
    <div id="page-auth">
      <Toaster position="top-right" reverseOrder={false} />
      <aside>
        <img
          src={illustrationImg}
          alt="Ilustração simbolizando perguntas e respostas."
        />
        <strong>Crie salas de Q&amp;E ao-vivo.</strong>
        <p>Tire as dúvidas da sua audência em tempo-real.</p>
      </aside>
      <main>
        <div className="main-content">
          <img src={logoImg} alt="Letmeask" />
          <button onClick={handleCreateRoom} className="create-room">
            <img src={googleIconImg} alt="Logo do Google" />
            Crie sua sala com o Google
          </button>
          <div className="separator">ou entre em uma sala</div>
          <form onSubmit={handleJoinRoom}>
            <input
              type="text"
              placeholder="Digite o código da sala"
              onChange={(event) => setRoomCode(event.target.value)}
              value={roomCode}
            />
            <Button type="submit">Entrar na sala</Button>
          </form>
        </div>
      </main>
    </div>
  );
}
Example #14
Source File: _app.tsx    From website with Apache License 2.0 4 votes vote down vote up
export default function App({Component, pageProps, router}: AppProps) {
	const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
	const [hasScrolled, setHasScrolled] = useState(false);

	const ballCanvas = useRef<HTMLDivElement>(null);

	const toggleMenu = () => {
		setMobileMenuOpen(old => !old);
	};

	useEffect(() => {
		if (mobileMenuOpen) {
			document.body.style.overflow = 'hidden';
			return;
		}

		document.body.style.overflow = 'unset';
	}, [mobileMenuOpen]);

	useEffect(() => {
		if (typeof window === 'undefined' || !ballCanvas.current) {
			return;
		}

		return loadCursor(ballCanvas.current);
	}, []);

	useEffect(() => {
		if (typeof window === 'undefined') {
			return;
		}

		setMobileMenuOpen(false);

		void new Audio('/pop.mp3').play().catch(() => null);
	}, [router.pathname]);

	useEffect(() => {
		if (typeof window === 'undefined') {
			return;
		}

		const listener = () => {
			setHasScrolled(window.scrollY > 20);
		};

		document.addEventListener('scroll', listener);

		return () => {
			document.removeEventListener('scroll', listener);
		};
	}, []);

	const closeMenu = () => {
		setMobileMenuOpen(false);
	};

	const navLinks = (
		<>
			<NavLink href="/" closeMenu={closeMenu}>
				/
			</NavLink>
			<NavLink href="/about" closeMenu={closeMenu}>
				/about
			</NavLink>
			<NavLink href="/talk" closeMenu={closeMenu}>
				/talk
			</NavLink>
			<li className="shrink-0">
				<a
					target="_blank"
					href="https://alistair.blog"
					rel="noreferrer"
					className={navlinkClassname}
				>
					notes ↗️
				</a>
			</li>
		</>
	);

	return (
		<StrictMode>
			<SWRConfig
				value={{
					fallback: {
						// SSR Lanyard's data
						[`lanyard:${DISCORD_ID}`]: pageProps?.lanyard as unknown,
						'https://gh-pinned-repos.egoist.sh/?username=alii':
							pageProps?.pinnedRepos as unknown,
					},
					fetcher,
				}}
			>
				<Toaster toastOptions={{position: 'top-left'}} />

				<Head>
					<title>Alistair Smith</title>
				</Head>

				<AnimatePresence>
					{mobileMenuOpen && (
						<motion.div
							initial={{opacity: 0, y: -10}}
							animate={{opacity: 1, y: 0}}
							exit={{opacity: 0}}
							className="fixed inset-0 z-10 py-24 px-8 space-y-2 bg-white dark:bg-gray-900 sm:hidden"
						>
							<h1 className="text-4xl font-bold">Menu.</h1>

							<ul className="grid grid-cols-1 gap-2">{navLinks}</ul>
						</motion.div>
					)}
				</AnimatePresence>

				<div className="overflow-hidden sticky top-0 z-20 h-32 transition-all sm:hidden">
					<div
						className={`${
							hasScrolled || mobileMenuOpen ? 'mt-0' : 'mt-10 mx-5'
						} bg-gray-100 dark:bg-gray-900 relative transition-all ${
							hasScrolled || mobileMenuOpen ? 'rounded-none' : 'rounded-lg'
						}`}
					>
						<div
							className={`pr-5 flex justify-between transition-colors space-x-2 ${
								mobileMenuOpen
									? 'bg-gray-100 dark:bg-gray-800'
									: 'bg-transparent'
							}`}
						>
							<button
								type="button"
								className="block relative z-50 px-2 text-gray-500 focus:ring transition-all"
								onClick={toggleMenu}
							>
								<Hamburger
									toggled={mobileMenuOpen}
									size={20}
									color="currentColor"
								/>
							</button>

							<div className="overflow-hidden py-2 px-1">
								<Song />
							</div>
						</div>
					</div>
				</div>

				<div className="py-10 px-5 mx-auto max-w-4xl">
					<div className="hidden items-center space-x-2 sm:flex">
						<nav className="flex-1">
							<ul className="flex space-x-4">{navLinks}</ul>
						</nav>

						<div className="overflow-hidden py-2 px-1">
							<Song />
						</div>
					</div>

					<main className="mx-auto space-y-12 max-w-3xl md:py-24">
						<Component {...pageProps} />
					</main>

					<footer className="p-4 py-10 mx-auto mt-20 max-w-3xl border-t-2 border-gray-900/10 dark:border-white/10 opacity-50">
						<h1 className="text-3xl font-bold">Alistair Smith</h1>
						<p>Software Engineer • {new Date().getFullYear()}</p>
					</footer>
				</div>

				<div
					ref={ballCanvas}
					className="fixed z-30 w-6 h-6 bg-transparent rounded-full border border-black dark:border-white shadow-md opacity-0 duration-200 pointer-events-none ball-transitions"
				/>
			</SWRConfig>
		</StrictMode>
	);
}
Example #15
Source File: notion.tsx    From pagely with MIT License 4 votes vote down vote up
Notion = () => {
  const {
    handleSubmit,
    register,
    setValue,
    formState: { errors },
  } = useForm<NewNotionSiteFormValues>({
    resolver: zodResolver(newNotionSiteSchema),
  });

  const [loading, setLoading] = useState<boolean>(false);
  const router = useRouter();

  useEffect(() => {
    router.prefetch('/dashboard');
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleFormSubmit = async (data: NewNotionSiteFormValues) => {
    setLoading(true);
    if (validateData(data) !== null) {
      setLoading(false);
      return;
    }
    const { name, description, subdomain, ogImageUrl, notionPageUrl } = data;
    const res = await axios.post('/api/new/notion', {
      siteName: name,
      siteDesc: description,
      subdomain,
      ogImageUrl,
      notionPageUrl,
    });
    if (res.data.success) {
      toast.success('Notion site created!');
      setLoading(false);
      router.push('/dashboard');
    } else if (res.data.success === false) {
      toast.error(res.data.error);
      setLoading(false);
    }
  };

  return (
    <MainLayout>
      <div>
        <div className='max-w-5xl mx-auto'>
          <h1 className='mt-10 text-4xl font-bold'>
            That&apos;s. Just fill out this quick form now
          </h1>
          <form
            className='max-w-sm mt-10'
            onSubmit={handleSubmit(handleFormSubmit)}>
            <label className='block'>
              <span className='mb-2 text-gray-700'>
                Subdomain (URL for your website)
                <InfoPopover content='This is the subdomain of your website. It is the part of the URL before the domain name. For example, in the image below thesubdomain is "one". (And its free!!)'>
                  <Image
                    placeholder='blur'
                    src={SubdomainImage}
                    alt='Subdomain'
                    className='inline-block w-full rounded'
                  />
                </InfoPopover>
              </span>
              <p className='mt-1 text-sm text-gray-600'>
                You cannot change this later
              </p>
              <div className='flex items-baseline'>
                <input
                  type='text'
                  className='inline-block w-full mt-1 border-gray-300 shadow-sm rounded-l-md focus:border-blue-300 focus:ring focus:ring-blue-200'
                  placeholder='elon'
                  {...register('subdomain')}
                />
                <span className='inline-block py-[0.5rem] select-none border-t border-b border-r pl-1 pr-2 bg-gray-100 rounded-r-md'>
                  .pagely.site
                </span>
              </div>
              <p className='mt-2 text-sm text-red-500'>
                {errors.subdomain && errors.subdomain.message}
              </p>
            </label>
            <label className='block mt-10'>
              <span className='mb-2 text-gray-700'>Name of your website</span>
              <InfoPopover content='This is the name of your website. It is also the title in Twitter cards and OG cards.'>
                <Image
                  placeholder='blur'
                  src={TweetTitleImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <p className='mt-1 text-sm text-gray-600'>
                This name will be used for generating OG title
              </p>
              <div className='flex items-center'>
                <input
                  type='text'
                  className='inline-block w-full mt-1 mr-1 border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200'
                  placeholder='Blog - Elon'
                  {...register('name')}
                />
              </div>
              <p className='mt-2 text-sm text-red-500'>
                {errors.name && errors.name.message}
              </p>
            </label>
            <label className='block mt-10'>
              <span className='text-gray-700'>Description</span>
              <InfoPopover content='This is the description of your website. It is also the description in Twitter cards and OG cards.'>
                <Image
                  placeholder='blur'
                  src={TweetDescImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <p className='mt-1 text-sm text-gray-600'>
                This description will be used for generating OG and Twitter description
              </p>
              <textarea
                className='block w-full mt-1 text-base border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50'
                rows={4}
                placeholder='Read my blog to...'
                {...register('description')}
              />
              <p className='mt-2 text-sm text-red-500'>
                {errors.description && errors.description.message}
              </p>
            </label>

            <label className='block mt-10'>
              <span className='text-gray-700'>OG Image URL</span>
              <InfoPopover content='This is the image that will appear in the OG cards and Twitter cards. 1200x630 is the recommended dimension for the OG image. If you do not need, just set it to https://no-og.image'>
                <Image
                  placeholder='blur'
                  src={OgImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <p className='mt-1 text-sm text-gray-600'>
                If left blank, the OG Image will be automatically generated from
                site name and Notion page&apos;s title!!
              </p>
              <div className='flex items-center'>
                <input
                  type='text'
                  className='inline-block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200'
                  placeholder='https://picsum.photos/1200/630'
                  {...register('ogImageUrl')}
                />
              </div>
              <p className='mt-2 text-sm text-red-500'>
                {errors.ogImageUrl && errors.ogImageUrl.message}
              </p>
              <div>
                <div className='inline-block px-2 py-px mt-2 text-sm text-gray-700 border border-gray-200 rounded cursor-pointer bg-gray-50 hover:bg-gray-100'>
                  <Dropzone
                    onDrop={(files) => {
                      uploadImage(files, setValue);
                    }}>
                    {({ getRootProps, getInputProps }) => (
                      <div {...getRootProps()}>
                        <input type='file' {...getInputProps()} />
                        <BiCloudUpload className='relative inline-block w-5 h-5 bottom-px' />{' '}
                        Upload image
                      </div>
                    )}
                  </Dropzone>
                </div>
                <p className='mt-1 text-sm text-gray-500'>
                  Or just drag &apos;n&apos; drop an image over the button !
                </p>
              </div>
            </label>

            <label className='block mt-10'>
              <span className='text-gray-700'>Notion Page URL</span>
              <InfoPopover content="You can find your Notion page URL in the Notion dashboard once you share the page to web. Pagely uses this URL to fetch the page's content.">
                <Image
                  placeholder='blur'
                  src={NotionImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <p className='mt-1 text-sm text-gray-600'>
                <span className="font-bold">Make sure your Notion page is public</span>. You will get the URL once you share your page to web
              </p>
              <input
                type='text'
                className='block w-full mt-1 text-base border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50'
                placeholder='https://notion.so/My-Notion-Page-...'
                {...register('notionPageUrl')}
              />
              <p className='mt-2 text-sm text-red-500'>
                {errors.notionPageUrl && errors.notionPageUrl.message}
              </p>
            </label>
            <button
              type='submit'
              className='inline-flex items-center justify-center my-10 text-lg font-medium text-white border border-transparent rounded shadow-md bg-custom-blue hover:bg-blue-700 focus:outline-none focus:ring-blue-500 focus:ring-2 focus:ring-offset-2'>
              {loading ? (
                <span className={`px-5 py-[6px] ${loading && 'py-[11px]'}`}>
                  <Loader height={18} width={200} color='#fff' type='Puff' />
                </span>
              ) : (
                <span className='px-5 py-[6px] '>
                  Get the website now -&gt;
                </span>
              )}
            </button>
          </form>
        </div>
      </div>
      <Toaster />
    </MainLayout>
  );
}
Example #16
Source File: github.tsx    From pagely with MIT License 4 votes vote down vote up
GitHub = () => {
  const [loading, setLoading] = useState<boolean>(false);
  const urlWithSession = useUrlWithSession('/api/new/github');
  const router = useRouter();

  useEffect(() => {
    router.prefetch('/dashboard');
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const {
    handleSubmit,
    register,
    control,
    formState: { errors },
  } = useForm<NewGitHubSiteFormValues>({
    resolver: zodResolver(newGitHubSiteSchema),
  });

  const handleFormSubmit = async (siteData: NewGitHubSiteFormValues) => {
    setLoading(true);
    axios
      .post(urlWithSession, {
        subdomain: siteData.subdomain,
        repoUrl: siteData.repoUrl,
        siteName: siteData.siteName,
      })
      .then((res) => {
        if (res.data.success) {
          setLoading(false);
          toast.success('Site created successfully');
          router.push('/dashboard');
        } else {
          setLoading(false);
          toast.error('There was an error creating your site');
        }
      })
      .catch(() => {
        setLoading(false);
        toast.error('There was an error creating your site');
      });
  };

  return (
    <MainLayout>
      {process.env.NODE_ENV !== 'production' && (
        <DevTool control={control} placement='top-right' />
      )}
      <div>
        <div className='max-w-5xl mx-auto'>
          <h1 className='mt-10 text-4xl font-bold'>
            That&apos;s. Just fill out this quick form now
          </h1>
          <form
            className='max-w-sm mt-10'
            onSubmit={handleSubmit(handleFormSubmit)}>
            <label className='block mt-10'>
              <span className='text-gray-700'>Site Name</span>
              <InfoPopover content='Name of your site. If OG image URL is not provided, this will be used for generating OG images'>
                <Image
                  placeholder='blur'
                  src={GitHubUrlImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <input
                type='text'
                className='block w-full mt-1 text-base border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50'
                placeholder='My awesome site'
                {...register('siteName', { required: true })}
              />
              <p className='mt-2 text-sm text-red-500'>
                {errors.siteName && errors.siteName.message}
              </p>
            </label>
            <label className='block mt-10'>
              <span className='mb-2 text-gray-700'>
                Subdomain (URL for your website)
                <InfoPopover content='This is the subdomain of your website. It is the part of the URL before the domain name. For example, in the image below thesubdomain is "one". (And its free!!)'>
                  <Image
                    placeholder='blur'
                    src={SubdomainImage}
                    alt='Subdomain'
                    className='inline-block w-full rounded'
                  />
                </InfoPopover>
              </span>
              <p className='mt-1 text-sm text-gray-600'>
                You cannot change this later
              </p>
              <div className='flex items-baseline'>
                <input
                  type='text'
                  className='inline-block w-full mt-1 border-gray-300 shadow-sm rounded-l-md focus:border-blue-300 focus:ring focus:ring-blue-200'
                  placeholder='elon'
                  {...register('subdomain', { required: true })}
                />
                <span className='inline-block py-[0.5rem] select-none border-t border-b border-r pl-1 pr-2 bg-gray-100 rounded-r-md'>
                  .pagely.site
                </span>
              </div>
              <p className='mt-2 text-sm text-red-500'>
                {errors.subdomain && errors.subdomain.message}
              </p>
            </label>
            <label className='block mt-10'>
              <span className='text-gray-700'>Repository URL</span>
              <InfoPopover content='This repo should contain a pagely.json file. It will be used to generate the website. Learn more about the schema at https://guides.pagely.site'>
                <Image
                  placeholder='blur'
                  src={GitHubUrlImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <p className='mt-1 mb-2 text-sm text-gray-600'>
                The URL of your GitHub repo which contains a{' '}
                <code className='p-[3px] bg-gray-100 rounded'>pagely.json</code>
              </p>
              <input
                type='text'
                className='block w-full mt-1 text-base border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50'
                placeholder='https://github.com/username/repo'
                {...register('repoUrl')}
              />
              <p className='mt-1 mb-2 text-sm text-gray-600'>
                Support for private repos coming soon!
              </p>
              <p className='mt-2 text-sm text-red-500'>
                {errors.repoUrl && errors.repoUrl.message}
              </p>
            </label>
            <button
              type='submit'
              className='inline-flex items-center justify-center my-10 text-lg font-medium text-white border border-transparent rounded shadow-md bg-custom-blue hover:bg-blue-700 focus:outline-none focus:ring-blue-500 focus:ring-2 focus:ring-offset-2'>
              {loading ? (
                <span className={`px-5 py-[6px] ${loading && 'py-[11px]'}`}>
                  <Loader height={18} width={200} color='#fff' type='Puff' />
                </span>
              ) : (
                <span className='px-5 py-[6px] '>
                  Get the website now -&gt;
                </span>
              )}
            </button>
          </form>
        </div>
      </div>
      <Toaster />
    </MainLayout>
  );
}
Example #17
Source File: SidebarLayout.tsx    From pagely with MIT License 4 votes vote down vote up
SidebarLayout: React.FC<{
  activeTab: 'code' | 'setup' | 'pages' | 'settings' | 'seo';
  title?: string;
}> = ({ activeTab, title, ...props }) => {
  const { emailAddresses, profileImageUrl, fullName, firstName } = useUser();
  const { signOut } = useClerk();

  const router = useRouter();
  const { data } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );
  return (
    <div>
      <div className='block lg:hidden'>
        <DashboardNav />
        <Head>
          <title>
            {title ||
              data?.siteName +
                ' - ' +
                activeTab.charAt(0).toUpperCase() +
                activeTab.slice(1) +
                ' | ' +
                'Pagely'}
          </title>
        </Head>
      </div>
      <div className='lg:flex'>
        {/* <div className='sticky top-0 overflow-y-hidden'> */}
        <div
          style={{ position: 'sticky' }}
          className='absolute top-0 h-screen left-0 px-10 py-5 bg-gray-50 w-[20vw] border-r hidden flex-col justify-between lg:flex'>
          <div>
            <Link href='/dashboard'>
              <a>
                <small className='text-gray-700 hover:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                  {' '}
                  {'<'}- Go back
                </small>
              </a>
            </Link>
            <ul className='mt-10'>
              <li
                className={`my-2 rounded ${
                  activeTab === 'setup' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={'/notion-site/' + data?.id}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <GoInbox className='relative inline-block bottom-[2px]' />{' '}
                    Setup
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'seo' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/seo`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <BiSearchAlt className='relative inline-block bottom-[2px]' />{' '}
                    SEO
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'code' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/code`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <BiCode className='relative inline-block bottom-[2px]' />{' '}
                    Code injection
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'pages' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/pages`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <HiOutlineNewspaper className='relative inline-block bottom-[2px]' />{' '}
                    Pages
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'settings'
                    ? ' bg-gray-200'
                    : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/settings`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <FiSettings className='relative inline-block bottom-[2px]' />{' '}
                    Settings
                  </a>
                </Link>
              </li>
            </ul>
          </div>
          <ProfileDropdown
            emailAddresses={emailAddresses}
            profileImageUrl={profileImageUrl}
            fullName={fullName}
            firstName={firstName}
            signOut={signOut}
          />
        </div>
        <div className='mx-10 mt-20'>{props.children}</div>
      </div>
      <Toaster />
    </div>
  );
}
Example #18
Source File: GitHubSiteLayout.tsx    From pagely with MIT License 4 votes vote down vote up
SidebarLayout: React.FC<{
  activeTab: 'code' | 'setup' | 'settings';
  title?: string;
}> = ({ activeTab, title, ...props }) => {
  const { emailAddresses, profileImageUrl, fullName, firstName } = useUser();
  const { signOut } = useClerk();

  const router = useRouter();
  const { data } = useClerkSWR<ghSites>(
    `/api/getSiteData/github/?siteId=${router.query.siteId}`
  );
  return (
    <div>
      <div className='block lg:hidden'>
        <DashboardNav />
        <Head>
          <title>
            {title ||
              data?.siteName +
                ' - ' +
                activeTab.charAt(0).toUpperCase() +
                activeTab.slice(1) +
                ' | ' +
                'Pagely'}
          </title>
        </Head>
      </div>
      <div className='lg:flex'>
        {/* <div className='sticky top-0 overflow-y-hidden'> */}
        <div
          style={{ position: 'sticky' }}
          className='absolute top-0 h-screen left-0 px-10 py-5 bg-gray-50 w-[20vw] border-r hidden flex-col justify-between lg:flex'>
          <div>
            <Link href='/dashboard'>
              <a>
                <small className='text-gray-700 hover:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                  {' '}
                  {'<'}- Go back
                </small>
              </a>
            </Link>
            <ul className='mt-10'>
              <li
                className={`my-2 rounded ${
                  activeTab === 'setup' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/github-site/${data?.id}`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <GoInbox className='relative inline-block bottom-[2px]' />{' '}
                    Setup
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'code' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/github-site/${data?.id}/code`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <BiCode className='relative inline-block bottom-[2px]' />{' '}
                    Code injection
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'settings'
                    ? ' bg-gray-200'
                    : ' hover:bg-gray-300'
                }`}>
                <Link href={`/github-site/${data?.id}/settings`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <FiSettings className='relative inline-block bottom-[2px]' />{' '}
                    Settings
                  </a>
                </Link>
              </li>
            </ul>
          </div>
          <ProfileDropdown
            emailAddresses={emailAddresses}
            profileImageUrl={profileImageUrl}
            fullName={fullName}
            firstName={firstName}
            signOut={signOut}
          />
        </div>
        <div className='mx-10 mt-20'>{props.children}</div>
      </div>
      <Toaster />
    </div>
  );
}
Example #19
Source File: Utility.tsx    From pagely with MIT License 4 votes vote down vote up
Utility = () => {
  const [color, setColor] = useState('#aabbcc');
  const [xOffset, setXOffset] = useState(10);
  const [yOffset, setYOffset] = useState(10);
  const [blur, setBlur] = useState(10);
  const [spread, setSpread] = useState(10);
  return (
    <div>
      <div>
        <h3 className='mb-3 text-xl font-bold'>Color Picker</h3>
        <div>
          <div>
            <HexColorInput
              color={color}
              onChange={setColor}
              className='px-1 py-px my-2 border border-gray-500 rounded-full focus:outline-none'
            />
            <HexColorPicker color={color} onChange={setColor} />
          </div>
          <div
            className='inline-flex px-2 py-px my-2 border border-gray-200 rounded-md cursor-pointer hover:bg-gray-100'
            onClick={() => {
              window.navigator.clipboard.writeText(color);
              toast.success(
                `Color - ${color.substr(1).toUpperCase()} copied to clipboard!`
              );
            }}>
            <span
              className='relative w-6 h-6 mr-2 rounded top-2'
              style={{ backgroundColor: color }}
            />
            <p className='my-2 mr-2 text-lg uppercase'>{color}</p>
            <HiOutlineClipboard className='relative w-8 h-8 top-1' />
          </div>
        </div>
        <hr className='w-full mx-auto my-5 text-gray-200' />
        <div>
          <h3 className='mb-3 text-xl font-bold'>Shadow generator</h3>
          <div className='flex items-center max-w-xl justify-evenly'>
            <div>
              <div className='mt-4'>
                <p className='mb-1 text-sm text-gray-600'>
                  X Offset: {xOffset}px
                </p>
                <Slider.Root
                  defaultValue={[xOffset]}
                  onValueChange={(value) => setXOffset(value[0])}
                  orientation='horizontal'
                  className='relative flex items-center w-52'>
                  <Slider.Track className='relative flex-grow h-3 bg-blue-100 rounded-full'>
                    <Slider.Range className='absolute h-full bg-gray-700 rounded-full' />
                  </Slider.Track>
                  <Slider.Thumb className='block w-6 h-6 bg-blue-300 rounded-full shadow-sm hover:bg-blue-500' />
                </Slider.Root>
              </div>
              <div className='mt-4'>
                <p className='mb-1 text-sm text-gray-600'>
                  Y Offset: {yOffset}px
                </p>
                <Slider.Root
                  defaultValue={[yOffset]}
                  onValueChange={(value) => setYOffset(value[0])}
                  orientation='horizontal'
                  className='relative flex items-center w-52'>
                  <Slider.Track className='relative flex-grow h-3 bg-blue-100 rounded-full'>
                    <Slider.Range className='absolute h-full bg-gray-700 rounded-full' />
                  </Slider.Track>
                  <Slider.Thumb className='block w-6 h-6 bg-blue-300 rounded-full shadow-sm hover:bg-blue-500' />
                </Slider.Root>
              </div>
              <div className='mt-4'>
                <p className='mb-1 text-sm text-gray-600'>Blur: {blur}px</p>
                <Slider.Root
                  defaultValue={[blur]}
                  onValueChange={(value) => setBlur(value[0])}
                  orientation='horizontal'
                  className='relative flex items-center w-52'>
                  <Slider.Track className='relative flex-grow h-3 bg-blue-100 rounded-full'>
                    <Slider.Range className='absolute h-full bg-gray-700 rounded-full' />
                  </Slider.Track>
                  <Slider.Thumb className='block w-6 h-6 bg-blue-300 rounded-full shadow-sm hover:bg-blue-500' />
                </Slider.Root>
              </div>
              <div className='mt-4'>
                <p className='mb-1 text-sm text-gray-600'>Spread: {spread}px</p>
                <Slider.Root
                  defaultValue={[spread]}
                  onValueChange={(value) => setSpread(value[0])}
                  orientation='horizontal'
                  className='relative flex items-center w-52'>
                  <Slider.Track className='relative flex-grow h-3 bg-blue-100 rounded-full'>
                    <Slider.Range className='absolute h-full bg-gray-700 rounded-full' />
                  </Slider.Track>
                  <Slider.Thumb className='block w-6 h-6 bg-blue-300 rounded-full shadow-sm hover:bg-blue-500' />
                </Slider.Root>
              </div>
              <p className='my-2 text-sm text-gray-600'>
                To change the color of the shadow, change the color in the color
                picker above.
              </p>
              <button
                className='px-2 py-px mt-2 border rounded cursor-pointer hover:bg-gray-100'
                onClick={() => {
                  toast.success(`Shadow's code copied to clipboard!`, {
                    position: 'bottom-center',
                  });
                  window.navigator.clipboard.writeText(
                    `box-shadow: ${xOffset}px ${yOffset}px ${blur}px ${spread}px ${color}px;`
                  );
                }}>
                Copy code
              </button>
            </div>
            <div className='inline-block'>
              <div
                className='w-24 h-24 max-w-md mx-auto mr-5 border border-gray-400 rounded'
                style={{
                  boxShadow: `${xOffset}px ${yOffset}px ${blur}px ${spread}px ${color}`,
                }}
              />
            </div>
          </div>
        </div>
        <hr className='w-full mx-auto my-5 text-gray-200' />
        <div>
          <h3 className='mb-3 text-xl font-bold'>Some resources...</h3>
          <ul>
            {resources.map((resource) => {
              return (
                <li key={resource.title} className='mt-1'>
                  <span className='text-gray-300 pointer-events-none select-none'>
                    {'-> '}
                  </span>
                  <a
                    href={resource.link}
                    target='_blank'
                    rel='noopener noreferrer'
                    className='text-base text-blue-600 hover:text-blue-700 hover:underline'>
                    {resource.title}
                  </a>
                </li>
              );
            })}
          </ul>
        </div>
      </div>
      <Toaster />
    </div>
  );
}