feat: ship a web app (#218)
* feat(orion): add endpoint for link metadata * refactor: cleanup comments * wip: plumbing for building a web app * setup deployment materials for web app * fix(web): favicon
This commit was merged in pull request #218.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
getAttachmentHandler,
|
||||
type AttachmentItem,
|
||||
} from "@/features/attachments/attachment-lightbox";
|
||||
import { platform } from "@/lib/platform";
|
||||
|
||||
export interface PendingAttachment {
|
||||
id: string;
|
||||
@@ -120,7 +121,7 @@ function LinkPreviewThumbnail({ entry }: { entry: LinkPreviewEntry }) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => window.electronLink.openExternal(metadata.url)}
|
||||
onClick={() => platform.link.openExternal(metadata.url)}
|
||||
className="flex h-16 w-28 shrink-0 flex-col justify-center gap-1 overflow-hidden rounded-lg bg-white/10 px-2 py-1.5 text-left transition-colors hover:bg-white/15"
|
||||
>
|
||||
<div className="flex items-center gap-1 text-[10px] text-white/40">
|
||||
|
||||
@@ -23,6 +23,8 @@ import { MAX_ATTACHMENT_SIZE_BYTES, MAX_ATTACHMENTS } from "@/lib/constants";
|
||||
import type { PendingAttachment } from "@/features/compose/attachment-strip";
|
||||
import { useSuspendPlayback } from "@/hooks/use-suspend-playback";
|
||||
import { useComposeIntentStore } from "@/stores/compose-intent-store";
|
||||
import { platform } from "@/lib/platform";
|
||||
import { requireDesktop } from "@/lib/platform/desktop-only";
|
||||
|
||||
export type ComposeStep = "idle" | "picking" | "recording" | "reviewing" | "typing" | "configuring" | "submitting";
|
||||
|
||||
@@ -512,6 +514,7 @@ export function ComposeOverlay({
|
||||
} else if (e.key === "s" || e.key === "S") {
|
||||
e.preventDefault();
|
||||
if (!guardIdle()) break;
|
||||
if (!requireDesktop("Screen recording")) break;
|
||||
setRecordingSource("screen");
|
||||
setStepSync("picking");
|
||||
} else if (e.key === "t" || e.key === "T") {
|
||||
@@ -594,7 +597,7 @@ export function ComposeOverlay({
|
||||
<ScreenSourcePicker
|
||||
title="Record your screen"
|
||||
confirmLabel="Record"
|
||||
getSources={window.electronScreen.getScreenSources}
|
||||
getSources={platform.screenRecord.getScreenSources}
|
||||
onSelect={handleScreenSourceSelected}
|
||||
onCancel={cancel}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { platform } from "@/lib/platform";
|
||||
import { requireDesktop } from "@/lib/platform/desktop-only";
|
||||
|
||||
const VIDEO_PREFERRED_MIME = "video/webm;codecs=vp9,opus";
|
||||
const VIDEO_FALLBACK_MIME = "video/webm";
|
||||
@@ -75,6 +77,7 @@ export function useScreenRecorder({
|
||||
|
||||
const startRecording = useCallback(
|
||||
async (sourceId: string) => {
|
||||
if (!requireDesktop("Screen recording")) return;
|
||||
try {
|
||||
// 1. Screen video
|
||||
const screenStream = await navigator.mediaDevices.getUserMedia({
|
||||
@@ -113,7 +116,7 @@ export function useScreenRecorder({
|
||||
const durationMs = Date.now() - startTimeRef.current;
|
||||
const blob = new Blob(chunksRef.current, { type: mime });
|
||||
stopAllTracks();
|
||||
window.electronScreen.stopRecordingWindow();
|
||||
platform.screenRecord.cancel();
|
||||
|
||||
if (blob.size > 0) {
|
||||
onFinishRef.current(blob, durationMs, mime);
|
||||
@@ -123,17 +126,17 @@ export function useScreenRecorder({
|
||||
recorder.start(1000);
|
||||
|
||||
// 4. Show floating control window
|
||||
window.electronScreen.startRecordingWindow();
|
||||
platform.screenRecord.start();
|
||||
|
||||
// 5. Listen for stop from floating window
|
||||
cleanupIpcRef.current = window.electronScreen.onStopRequested(() => {
|
||||
cleanupIpcRef.current = platform.screenRecord.onStopRequested(() => {
|
||||
if (recorderRef.current?.state === "recording") {
|
||||
recorderRef.current.stop();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
stopAllTracks();
|
||||
window.electronScreen.stopRecordingWindow();
|
||||
platform.screenRecord.cancel();
|
||||
onErrorRef.current(
|
||||
err instanceof Error ? err.message : "Failed to start screen recording",
|
||||
);
|
||||
@@ -157,14 +160,14 @@ export function useScreenRecorder({
|
||||
}
|
||||
}
|
||||
stopAllTracks();
|
||||
window.electronScreen.stopRecordingWindow();
|
||||
platform.screenRecord.cancel();
|
||||
}, [stopAllTracks]);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
stopAllTracks();
|
||||
window.electronScreen.stopRecordingWindow();
|
||||
platform.screenRecord.cancel();
|
||||
};
|
||||
}, [stopAllTracks]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user