v0.1.8
Menu
Download

React 19 Core

The desktop UI is React 19 inside Tauri webviews. Tabs replace a router; Zustand picks the active surface.

main.tsx checks getCurrentWindow().label and mounts either App, MiniPlayer, or NotifyOverlayApp. Same React 19 + StrictMode entry for each webview label.

App.tsx is the shell: sidebar nav sets activeTab in Zustand (downloader, explorer, media, player, settings). AnimatePresence swaps the major views. Explorer is special: the tab body is mostly a positioned host div because the child webview paints on top.

Heavy feature UIs are split components. Downloader logic sits in useDownloaderView.ts with UI in DownloaderView.tsx and DownloadJobQueuePanel.tsx. Player splits outer PlayerView (nullable playingFile guard) from inner PlayerViewWithFile so hooks never run without a file. Settings uses nested collapsible trees for SponsorBlock and playback prefs.

Mini player is a separate bundle with duplicated playback UI state (progress, hover, layout mode). It listens for Tauri events instead of subscribing to the main store. Fast refresh works under npm run tauri dev the same as plain Vite.

In the repo

const rootEl = document.getElementById("root") as HTMLElement;
const label = getCurrentWindow().label;

if (import.meta.env.DEV && label === "main") {
  void import("./devScreenshotFrame").then(({ installDevScreenshotFrame }) => {
    installDevScreenshotFrame();
  });
}

const tree = label === "notify" ? <NotifyOverlayApp /> : <App />;

ReactDOM.createRoot(rootEl).render(<React.StrictMode>{tree}</React.StrictMode>);
            className={`absolute inset-0 ${activeTab === "explorer" ? "overflow-hidden" : "overflow-y-auto"}`}
          >
            <AnimatePresence mode="wait">
              {activeTab === "downloader" && (
                <DownloaderView
                  key="downloader"
                  internalDir={RUFORGE_INTERNAL_DIR}
                  storageFull={storageBlocksNewDownloads}
                />
              )}
              {activeTab === "explorer" && (
                <div className="absolute inset-0 min-h-0 bg-[#1D1613] overflow-hidden">
                  <div
                    ref={explorerWebviewHostRef}
                    className="fixed z-[1] top-10 bottom-0 right-0 pointer-events-none transition-[left] duration-500 ease-[0.23,1,0.32,1]"
                    style={{ left: sidebarChromeLeft }}
                    aria-hidden
                  />
                  {/* Shimmer Placeholder */}
                  <div className="absolute inset-0 z-0 flex flex-col p-8 space-y-8 animate-pulse pointer-events-none">
                    <div className="h-12 w-1/3 bg-white/5 rounded-2xl" />
                    <div className="grid grid-cols-4 gap-6 flex-1">
                      {[...Array(8)].map((_, i) => (
                        <div key={i} className="aspect-video bg-white/5 rounded-[24px]" />
                      ))}
                    </div>
                  </div>
                </div>
              )}
              {activeTab === "media" && (
                selectedPlaylist ? (
                  <PlaylistDetailView 
                    key={`playlist-${selectedPlaylist.path}`}
                    playlist={selectedPlaylist}
                    onBack={() => setSelectedPlaylist(null)}
                  />
                ) : (
                  <MediaView 
                    key="media" 
                    onPlaylistClick={(p) => setSelectedPlaylist(p)}
                  />
                )
              )}
              {activeTab === "player" && playingFile && (
                <PlayerView
                  ref={playerViewRef}
                  key={`player-${playingFile.path}`}
                  onBack={() => setActiveTab("media")}
                />
              )}
                                    initial={{ height: 0, opacity: 0 }}
                                    animate={{ height: "auto", opacity: 1 }}
                                    exit={{ height: 0, opacity: 0 }}
                                    transition={{ duration: 0.2, ease: "easeOut" }}
                                    className="px-2 pb-2 space-y-0.5 overflow-hidden"
                                  >
                                    <button
                                      type="button"
                                      onClick={() => { setIsSubtitlesEnabled(false); onSubtitleToggle?.(false); setShowSubtitleMenu(false); }}

Where it shows up

  • main.tsx webview label routing
  • App.tsx tab shell, window chrome, event listeners
  • PlayerView.tsx, MediaView.tsx, DownloaderView.tsx, SettingsView.tsx
  • MiniPlayer.tsx second-window playback UI