diff --git a/src/App.tsx b/src/App.tsx index ffc3f4d..c15edc4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { type Component, createSignal, Show, onMount, onCleanup, lazy, Suspense } from 'solid-js'; +import { type Component, createSignal, onMount, onCleanup, createMemo, lazy, Suspense, Show } from 'solid-js'; import { Layout } from './components/Layout'; import { EmbedLayout } from './components/EmbedLayout'; import { EmbedAuthWrapper } from './components/EmbedAuthWrapper'; @@ -23,8 +23,13 @@ const App: Component = () => { // Basic routing state const [currentView, setCurrentView] = createSignal("critical"); const [isAuthenticated, setIsAuthenticated] = createSignal(pb.authStore.isValid); + const [location, setLocation] = createSignal(window.location.href); onMount(() => { + const handleLocChange = () => setLocation(window.location.href); + window.addEventListener('popstate', handleLocChange); + window.addEventListener('hashchange', handleLocChange); + const removeListener = pb.authStore.onChange((token) => { console.log('[DEBUG] pb.authStore.onChange fired, token present:', !!token); setIsAuthenticated(!!token); @@ -33,7 +38,11 @@ const App: Component = () => { } }, true); - onCleanup(() => removeListener()); + onCleanup(() => { + removeListener(); + window.removeEventListener('popstate', handleLocChange); + window.removeEventListener('hashchange', handleLocChange); + }); // Background preload of other views when idle const idleCallback = (window as any).requestIdleCallback || ((cb: any) => setTimeout(cb, 1000)); @@ -59,15 +68,19 @@ const App: Component = () => { // Determine if we are in an embed route (check both path and hash for compatibility) const isEmbed = () => { - const path = window.location.pathname; - const hash = window.location.hash; + const loc = location(); // Reactive dependency + const url = new URL(loc); + const path = url.pathname; + const hash = url.hash; const res = path.startsWith('/embed/') || hash.startsWith('#/embed/'); - console.log('[DEBUG] isEmbed check:', { res, path, hash, href: window.location.href }); + console.log('[DEBUG] isEmbed check:', { res, path, hash, href: loc }); return res; }; const getEmbedView = () => { - const fullPath = window.location.pathname + window.location.hash; + const loc = location(); // Reactive dependency + const url = new URL(loc); + const fullPath = url.pathname + url.hash; let view = null; if (fullPath.includes('/notes')) view = 'embed_notes'; else if (fullPath.includes('/quick-add')) view = 'embed_quick_add'; @@ -101,10 +114,12 @@ const App: Component = () => {
}> {(() => { - const searchParams = new URLSearchParams(window.location.search); - const noteIdFromUrl = searchParams.get('noteId'); - const [selectedNoteId, setSelectedNoteId] = createSignal(noteIdFromUrl); - return ; + const noteIdFromUrl = createMemo(() => { + const params = new URLSearchParams(new URL(location()).search); + return params.get('noteId'); + }); + console.log('[DEBUG App] Rendering embed/notes context. noteId trace:', noteIdFromUrl()); + return { }} hideNavigation={!!noteIdFromUrl()} />; })()} diff --git a/src/views/NotepadView.tsx b/src/views/NotepadView.tsx index d1ca49f..2f7e03e 100644 --- a/src/views/NotepadView.tsx +++ b/src/views/NotepadView.tsx @@ -23,9 +23,7 @@ export const NotepadView: Component<{ // Derived states const activeNote = createMemo(() => { const id = props.selectedNoteId?.trim(); - const note = store.notes.find(n => n.id === id) || null; - console.log('[DEBUG NotepadView] store.notes length:', store.notes.length, 'selectedNoteId:', id, 'found Note:', !!note); - return note; + return store.notes.find(n => n.id === id) || null; }); const handleUpdateNote = async (id: string, data: Partial) => { diff --git a/test-embed.html b/test-embed.html index 29146f8..5644486 100644 --- a/test-embed.html +++ b/test-embed.html @@ -160,11 +160,12 @@

2. Creating Notes Programmatically (API):

Before embedding, a sister app can create a Note via PocketBase API to retrieve a new noteId. By default, notes should have an array of tags and a - title.

+ title. +

Using the PocketBase JS SDK:

-const record = await pb.collection('notes').create({
+const record = await pb.collection('TasGrid_Notes').create({
     title: "Sister App Payload",
     content: "<p>Initial content here...</p>",
     tags: ["sister_app_export"],
@@ -178,7 +179,7 @@ const newNoteId = record.id;
                     

Using standard REST API (fetch):

-const res = await fetch('https://pocketbase.ccllc.pro/api/collections/notes/records', {
+const res = await fetch('https://pocketbase.ccllc.pro/api/collections/TasGrid_Notes/records', {
     method: 'POST',
     headers: {
         'Content-Type': 'application/json',
@@ -197,14 +198,24 @@ const newNoteId = data.id;

3. Authentication Protocol:

The parent application must send a postMessage to the iframe immediately after the - iframe loads (or whenever auth state changes).

+ iframe loads (or whenever auth state changes). Since iframes reset their internal state on + navigation, + you should always sync auth on the onload event.

+

Example using vanilla JS:

-iframe.contentWindow.postMessage({
-  type: "TASGRID_AUTH",
-  token: "YOUR_POCKETBASE_TOKEN",
-  user: { /* optional PB user record */ }
-}, "*");
+// 1. Define sync function +function syncAuth(iframe) { + iframe.contentWindow.postMessage({ + type: "TASGRID_AUTH", + token: pb.authStore.token, + user: pb.authStore.model + }, "*"); +} + +// 2. Attach to iframe (either in HTML or via JS) +// <iframe onload="syncAuth(this)" src="..."></iframe> +

4. Responsiveness:

Both routes are designed to be fluid. Ensure your iframe container has defined dimensions; the @@ -221,7 +232,7 @@ iframe.contentWindow.postMessage({ Notes Embed /embed/notes - +

@@ -230,7 +241,8 @@ iframe.contentWindow.postMessage({ Quick Add Embed /embed/quick-add
- + @@ -238,6 +250,14 @@ iframe.contentWindow.postMessage({ const pb = new PocketBase('https://pocketbase.ccllc.pro'); const statusEl = document.getElementById('status'); + function syncAuthOnLoad(iframe) { + console.log(`Iframe ${iframe.id} loaded, checking auth sync...`); + if (pb.authStore.isValid) { + console.log(`Syncing existing auth to ${iframe.id}`); + sendAuthToIframes(); + } + } + function loadSpecificNote() { const id = document.getElementById('note-id-input').value.trim(); const iframe = document.getElementById('notes-iframe'); @@ -261,7 +281,7 @@ iframe.contentWindow.postMessage({ try { // Using PocketBase SDK to mimic a REST API call from sister app - const record = await pb.collection('notes').create({ + const record = await pb.collection('TasGrid_Notes').create({ title: title, content: "

This note was created automatically via the API script!

", tags: ["api_generated"],