Add a typed platform package to decouple the frontend from Tauri (#539)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-08-14 12:44:01 -07:00
committed by GitHub
co-authored by Claude Opus 5
parent 0068be9ffc
commit 2383f06e71
107 changed files with 954 additions and 505 deletions
@@ -1,5 +1,5 @@
import { convertFileSrc } from "@tauri-apps/api/core";
import { useEffect, useState } from "react";
import { platform } from "@yaakapp-internal/platform";
interface Props {
bodyPath?: string;
@@ -12,7 +12,7 @@ export function AudioViewer({ bodyPath, data, mimeType }: Props) {
useEffect(() => {
if (bodyPath) {
setSrc(convertFileSrc(bodyPath));
setSrc(platform.files.url(bodyPath));
} else if (data) {
// The type matters here in a way it doesn't for an image: a media element goes by what
// the blob declares rather than sniffing it, so an Ogg labelled as MP3 won't play
@@ -1,6 +1,6 @@
import { convertFileSrc } from "@tauri-apps/api/core";
import classNames from "classnames";
import { useEffect, useState } from "react";
import { platform } from "@yaakapp-internal/platform";
type Props = { className?: string; mimeType?: string } & (
| {
@@ -18,7 +18,7 @@ export function ImageViewer({ className, mimeType, ...props }: Props) {
useEffect(() => {
if (bodyPath != null) {
setSrc(convertFileSrc(bodyPath));
setSrc(platform.files.url(bodyPath));
} else if (data != null) {
const blob = new Blob([data], { type: mimeType ?? "image/png" });
const url = URL.createObjectURL(blob);
@@ -1,12 +1,12 @@
import "react-pdf/dist/Page/TextLayer.css";
import "react-pdf/dist/Page/AnnotationLayer.css";
import { convertFileSrc } from "@tauri-apps/api/core";
import "./PdfViewer.css";
import type { PDFDocumentProxy } from "pdfjs-dist";
import { useMemo, useRef, useState } from "react";
import { Document, Page } from "react-pdf";
import { useContainerSize } from "@yaakapp-internal/ui";
import { fireAndForget } from "../../lib/fireAndForget";
import { platform } from "@yaakapp-internal/platform";
fireAndForget(
import("react-pdf").then(({ pdfjs }) => {
@@ -37,7 +37,7 @@ export function PdfViewer({ bodyPath, data }: Props) {
// `Document` renders its "Failed to load PDF file" state for that frame before recovering
const src = useMemo(() => {
if (bodyPath) {
return convertFileSrc(bodyPath);
return platform.files.url(bodyPath);
}
if (data) {
// Create a copy to avoid "Buffer is already detached" errors
@@ -1,5 +1,5 @@
import { convertFileSrc } from "@tauri-apps/api/core";
import { useEffect, useState } from "react";
import { platform } from "@yaakapp-internal/platform";
interface Props {
bodyPath?: string;
@@ -12,7 +12,7 @@ export function VideoViewer({ bodyPath, data, mimeType }: Props) {
useEffect(() => {
if (bodyPath) {
setSrc(convertFileSrc(bodyPath));
setSrc(platform.files.url(bodyPath));
} else if (data) {
// As in AudioViewer: a media element trusts the declared type instead of sniffing
const blob = new Blob([new Uint8Array(data)], { type: mimeType ?? "video/mp4" });