fix: proper opening of the mac app on bookmarklet
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { ActivityBar, Sidebar, Editor, StatusBar, Panel, TabBar, ToastContainer, showToast, ResizablePanel, WindowTitleBar } from './components';
|
||||
import { useAppStore, PostData, MediaData, TaskProgress } from './store';
|
||||
import { loadTabsForProject, saveTabsForProject } from './utils';
|
||||
import { openEntityTab, openSingletonToolTab } from './navigation/tabPolicy';
|
||||
import { openSingletonToolTab } from './navigation/tabPolicy';
|
||||
import { persistSiteValidationReport } from './navigation/siteValidationPersistence';
|
||||
import { executeActivityClick } from './navigation/activityExecution';
|
||||
import { handleBlogmarkCreatedEvent } from './navigation/blogmarkHandling';
|
||||
import { createDeferredEventGate } from './navigation/deferredEventGate';
|
||||
import { createAndFocusPost } from './navigation/postCreation';
|
||||
import { ensureRendererPicoThemeStylesheet, getRendererPicoTheme } from './utils/picoTheme';
|
||||
import { useI18n } from './i18n';
|
||||
@@ -33,6 +35,25 @@ const App: React.FC = () => {
|
||||
openTab,
|
||||
restoreTabState,
|
||||
} = useAppStore();
|
||||
const blogmarkEventGateRef = useRef(createDeferredEventGate<PostData>());
|
||||
|
||||
const processBlogmarkCreated = (created: PostData) => {
|
||||
addPost(created);
|
||||
const state = useAppStore.getState();
|
||||
handleBlogmarkCreatedEvent(
|
||||
{
|
||||
activeView: state.activeView,
|
||||
sidebarVisible: state.sidebarVisible,
|
||||
},
|
||||
created,
|
||||
{
|
||||
setActiveView: state.setActiveView,
|
||||
toggleSidebar: state.toggleSidebar,
|
||||
setSelectedPost: state.setSelectedPost,
|
||||
openTab: state.openTab,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
// Load initial data
|
||||
useEffect(() => {
|
||||
@@ -80,6 +101,9 @@ const App: React.FC = () => {
|
||||
console.error('Failed to load initial data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setTimeout(() => {
|
||||
blogmarkEventGateRef.current.markReady(processBlogmarkCreated);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,28 +240,12 @@ const App: React.FC = () => {
|
||||
|
||||
unsubscribers.push(
|
||||
window.electronAPI?.on('blogmark:created', (post: unknown) => {
|
||||
const created = post as { id?: string } | null;
|
||||
const created = post as PostData;
|
||||
if (!created?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = useAppStore.getState();
|
||||
executeActivityClick(
|
||||
{
|
||||
activeView: state.activeView,
|
||||
sidebarVisible: state.sidebarVisible,
|
||||
tabs: state.tabs,
|
||||
activeTabId: state.activeTabId,
|
||||
},
|
||||
'posts',
|
||||
{
|
||||
setActiveView: state.setActiveView,
|
||||
toggleSidebar: state.toggleSidebar,
|
||||
},
|
||||
);
|
||||
|
||||
state.setSelectedPost(created.id);
|
||||
openEntityTab(state.openTab, 'post', created.id, 'preview');
|
||||
blogmarkEventGateRef.current.push(created, processBlogmarkCreated);
|
||||
}) || (() => {})
|
||||
);
|
||||
|
||||
@@ -475,6 +483,10 @@ const App: React.FC = () => {
|
||||
}) || (() => {})
|
||||
);
|
||||
|
||||
void window.electronAPI?.app.notifyRendererReady?.().catch((error) => {
|
||||
console.error('Failed to notify renderer readiness:', error);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribers.forEach(unsub => unsub());
|
||||
};
|
||||
|
||||
40
src/renderer/navigation/blogmarkHandling.ts
Normal file
40
src/renderer/navigation/blogmarkHandling.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { openEntityTab } from './tabPolicy';
|
||||
import type { SidebarView } from './sidebarViewRegistry';
|
||||
|
||||
interface BlogmarkStateSnapshot {
|
||||
activeView: SidebarView;
|
||||
sidebarVisible: boolean;
|
||||
}
|
||||
|
||||
interface BlogmarkCreatedPayload {
|
||||
id?: string;
|
||||
}
|
||||
|
||||
interface BlogmarkHandlers {
|
||||
setActiveView: (view: SidebarView) => void;
|
||||
toggleSidebar: () => void;
|
||||
setSelectedPost: (id: string) => void;
|
||||
openTab: (tab: { type: 'post'; id: string; isTransient: boolean }) => void;
|
||||
}
|
||||
|
||||
export function handleBlogmarkCreatedEvent(
|
||||
snapshot: BlogmarkStateSnapshot,
|
||||
payload: BlogmarkCreatedPayload | null | undefined,
|
||||
handlers: BlogmarkHandlers,
|
||||
): void {
|
||||
const postId = typeof payload?.id === 'string' ? payload.id : '';
|
||||
if (!postId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (snapshot.activeView !== 'posts') {
|
||||
handlers.setActiveView('posts');
|
||||
}
|
||||
|
||||
if (!snapshot.sidebarVisible) {
|
||||
handlers.toggleSidebar();
|
||||
}
|
||||
|
||||
handlers.setSelectedPost(postId);
|
||||
openEntityTab(handlers.openTab, 'post', postId, 'preview');
|
||||
}
|
||||
35
src/renderer/navigation/deferredEventGate.ts
Normal file
35
src/renderer/navigation/deferredEventGate.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export interface DeferredEventGate<T> {
|
||||
push: (event: T, consume: (event: T) => void) => void;
|
||||
markReady: (consume: (event: T) => void) => void;
|
||||
isReady: () => boolean;
|
||||
}
|
||||
|
||||
export function createDeferredEventGate<T>(): DeferredEventGate<T> {
|
||||
let ready = false;
|
||||
let queue: T[] = [];
|
||||
|
||||
return {
|
||||
push: (event, consume) => {
|
||||
if (ready) {
|
||||
consume(event);
|
||||
return;
|
||||
}
|
||||
|
||||
queue.push(event);
|
||||
},
|
||||
markReady: (consume) => {
|
||||
if (ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
ready = true;
|
||||
const queuedEvents = queue;
|
||||
queue = [];
|
||||
|
||||
for (const event of queuedEvents) {
|
||||
consume(event);
|
||||
}
|
||||
},
|
||||
isReady: () => ready,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user