From 227033d316de66abd8b8d16f084d8c909fbee4db Mon Sep 17 00:00:00 2001 From: Silberengel Date: Thu, 26 Feb 2026 19:50:58 +0100 Subject: [PATCH] refactor 9 Nostr-Signature: 0d92496bc69fe5a2005be0eba26653a729d358f9d9f227e1af01c330eb0c4387 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 9203dcc9cfb44804957d37d3b47079ac324bffb42e445a3a79130622e5e20fd10513d987f48edf195514ebf6cb136ba6c5992b39de21b8b47a086194e22cbaeb --- nostr/commit-signatures.jsonl | 1 + src/routes/repos/[npub]/[repo]/+page.svelte | 27 ++-- .../[npub]/[repo]/components/DocsTab.svelte | 152 ++++++++++-------- .../[repo]/components/HistoryTab.svelte | 16 +- .../[npub]/[repo]/components/IssuesTab.svelte | 8 +- .../[npub]/[repo]/components/PRsTab.svelte | 8 +- .../[repo]/components/PatchesTab.svelte | 8 +- .../[repo]/components/StatusTabLayout.svelte | 53 +++++- .../[npub]/[repo]/components/TabLayout.svelte | 19 ++- .../dialogs/CreateIssueDialog.svelte | 27 +++- .../components/dialogs/CreatePRDialog.svelte | 27 +++- .../dialogs/CreatePatchDialog.svelte | 26 ++- .../[repo]/components/dialogs/Modal.svelte | 5 +- 13 files changed, 269 insertions(+), 108 deletions(-) diff --git a/nostr/commit-signatures.jsonl b/nostr/commit-signatures.jsonl index 1257ae4..bca65eb 100644 --- a/nostr/commit-signatures.jsonl +++ b/nostr/commit-signatures.jsonl @@ -101,3 +101,4 @@ {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772111536,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 5"]],"content":"Signed commit: refactor 5","id":"47651ed0aee8072f356fbac30b6168f2c985bcca392f9ed7d7c38d9670d90f16","sig":"2ca5d04d4a619dc3e02962249f7c650e3a561315897b329f4493e87148c5dd89fbcb6694515a72d0d17e64c9930e57bd7761e27b353275bb1ada9449330f4e1c"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112054,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 6"]],"content":"Signed commit: refactor 6","id":"cd9b7e015ee3bd6a4c4ab7d54d90ab411a08c29f249158c4cdea2b12996b6b44","sig":"2a8fd0a3718169df1517c0b939ec9ea9793da4dc07b20d9366f09fe70b5268e94451916f975e2cea1a3741419440189d31f844e79863e84de00c0be7c449e92a"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772112920,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 7"]],"content":"Signed commit: refactor 7","id":"80f54ac61390cfbc8f2496a162d7065c447033a2e085ab5886c8138e337e93f9","sig":"f64bd2c965eff3534ad68e245651c189dc925d9613dd85557d88af8c692361ade13ccdd9deb88ae07eb227aa002af99d525a7fdf6f29eca854b5a02882ef226f"} +{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772130529,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","refactor 8"]],"content":"Signed commit: refactor 8","id":"716cfe7b5d8b788e6e24092a6ad7e92de0b3d383c43a343f3c5bec4d2bbdd4b9","sig":"e80ed3d9d471bd6907e212edfd7cf3f6039fa80e4434c35f0591729515eaa98c7a8ac54f2ac6f7a2fefb7846de0e2f0a120543a0dbe862c47c7710a653189b0c"} diff --git a/src/routes/repos/[npub]/[repo]/+page.svelte b/src/routes/repos/[npub]/[repo]/+page.svelte index 97d4570..e344691 100644 --- a/src/routes/repos/[npub]/[repo]/+page.svelte +++ b/src/routes/repos/[npub]/[repo]/+page.svelte @@ -294,26 +294,19 @@ const lastBranch = { value: null as string | null }; // Initialize activeTab from URL query parameter + // Sync activeTab to match URL state $effect(() => { if (typeof window === 'undefined' || !state.isMounted) return; const tabFromQuery = $page.url.searchParams.get('tab'); const validTabs = ['docs', 'files', 'issues', 'prs', 'patches', 'discussions', 'history', 'tags', 'code-search']; - if (tabFromQuery && validTabs.includes(tabFromQuery)) { - // Update from URL query parameter - if (tabFromQuery !== state.ui.activeTab) { - state.ui.activeTab = tabFromQuery as typeof state.ui.activeTab; - } - } else if (!tabFromQuery) { - // No tab in query params - 'files' is the default (no param = files tab) - // Only set default if activeTab is not already a valid tab - if (!validTabs.includes(state.ui.activeTab)) { - state.ui.activeTab = 'files'; - } - // If activeTab is already 'files', do nothing (user is on files tab) - // If activeTab is another valid tab but URL has no param, don't override - // This allows onTabChange handlers to manage state without interference + // Determine what tab the URL represents + const urlTab = tabFromQuery && validTabs.includes(tabFromQuery) ? tabFromQuery : 'files'; + + // Only update if activeTab doesn't match URL state + if (state.ui.activeTab !== urlTab) { + state.ui.activeTab = urlTab as typeof state.ui.activeTab; } }); @@ -2325,6 +2318,8 @@ } goto(url.pathname + url.search, { replaceState: true, noScroll: true }); }} + onCreate={() => { state.openDialog = 'createIssue'; }} + userPubkey={state.user.pubkey || null} /> {/if} @@ -2385,6 +2380,8 @@ } goto(url.pathname + url.search, { replaceState: true, noScroll: true }); }} + onCreate={() => { state.openDialog = 'createPR'; }} + userPubkey={state.user.pubkey || null} /> {/if} @@ -2466,6 +2463,8 @@ } goto(url.pathname + url.search, { replaceState: true, noScroll: true }); }} + onCreate={() => { state.openDialog = 'createPatch'; }} + userPubkey={state.user.pubkey || null} /> {/if} diff --git a/src/routes/repos/[npub]/[repo]/components/DocsTab.svelte b/src/routes/repos/[npub]/[repo]/components/DocsTab.svelte index 78eb6cd..eddfe26 100644 --- a/src/routes/repos/[npub]/[repo]/components/DocsTab.svelte +++ b/src/routes/repos/[npub]/[repo]/components/DocsTab.svelte @@ -36,9 +36,11 @@ let documentationKind = $state<'markdown' | 'asciidoc' | 'text' | '30040' | null>(null); let indexEvent = $state(null); let loading = $state(false); + let loadingDocs = $state(false); let error = $state(null); let docFiles: Array<{ name: string; path: string }> = $state([]); let selectedDoc: string | null = $state(null); + let hasReadme = $state(false); $effect(() => { if (npub && repo && currentBranch) { @@ -48,83 +50,67 @@ async function loadDocumentation() { loading = true; + loadingDocs = true; error = null; documentationContent = null; documentationKind = null; indexEvent = null; + hasReadme = false; try { logger.operation('Loading documentation', { npub, repo, branch: currentBranch }); - // Try README first (faster, always available if repo has content) - const readmePromise = (async () => { - try { - const readmeResponse = await fetch(`/api/repos/${npub}/${repo}/readme?ref=${currentBranch || 'HEAD'}`); - if (readmeResponse.ok) { - const readmeData = await readmeResponse.json(); - if (readmeData.content) { - return { - content: readmeData.content, - kind: readmeData.type || 'markdown', - path: 'README.md' - }; - } + // Load README FIRST and display immediately + try { + const readmeResponse = await fetch(`/api/repos/${npub}/${repo}/readme?ref=${currentBranch || 'HEAD'}`); + if (readmeResponse.ok) { + const readmeData = await readmeResponse.json(); + if (readmeData.content) { + documentationContent = readmeData.content; + documentationKind = readmeData.type || 'markdown'; + selectedDoc = 'README.md'; + hasReadme = true; + loading = false; // Stop showing loading once README is loaded + logger.debug({ npub, repo }, 'README loaded and displayed'); } - } catch (readmeErr) { - logger.debug({ error: readmeErr, npub, repo }, 'No README found'); } - return null; - })(); + } catch (readmeErr) { + logger.debug({ error: readmeErr, npub, repo }, 'No README found'); + } - // Try docs folder in parallel - const docsPromise = (async () => { - try { - const response = await fetch(`/api/repos/${npub}/${repo}/tree?ref=${currentBranch || 'HEAD'}&path=docs`); - if (response.ok) { - const data = await response.json(); - return Array.isArray(data) ? data : (data.files || []); + // Now check for docs folder in the background + try { + const response = await fetch(`/api/repos/${npub}/${repo}/tree?ref=${currentBranch || 'HEAD'}&path=docs`); + if (response.ok) { + const data = await response.json(); + const docsFiles = Array.isArray(data) ? data : (data.files || []); + + if (docsFiles.length > 0) { + docFiles = docsFiles; + logger.debug({ npub, repo, fileCount: docsFiles.length }, 'Docs folder found'); } - } catch (err) { - logger.debug({ error: err, npub, repo }, 'Docs folder not found'); - } - return []; - })(); - - // Wait for both, prefer docs folder if it has files - const [readmeResult, docsFiles] = await Promise.all([readmePromise, docsPromise]); - docFiles = docsFiles; - - if (docsFiles.length > 0) { - // Look for README or index files first in docs folder - const readmeFile = docsFiles.find((f: { name: string; path: string }) => - f.name.toLowerCase() === 'readme.md' || - f.name.toLowerCase() === 'readme.adoc' || - f.name.toLowerCase() === 'index.md' - ); - - if (readmeFile) { - await loadDocFile(readmeFile.path); - } else { - // Load first file from docs folder - await loadDocFile(docsFiles[0].path); } - } else if (readmeResult) { - // No docs folder, use README from root - documentationContent = readmeResult.content; - documentationKind = readmeResult.kind as 'markdown' | 'asciidoc'; - selectedDoc = readmeResult.path; + } catch (err) { + logger.debug({ error: err, npub, repo }, 'Docs folder not found'); } - // Check for kind 30040 publication index (only if no content found yet) - if (!documentationContent && !indexEvent) { + // Check for kind 30040 publication index (only if no README found) + if (!hasReadme && !indexEvent) { await checkForPublicationIndex(); + if (indexEvent) { + loading = false; + } } } catch (err) { error = err instanceof Error ? err.message : 'Failed to load documentation'; logger.error({ error: err, npub, repo }, 'Error loading documentation'); - } finally { loading = false; + } finally { + loadingDocs = false; + if (!hasReadme && !indexEvent) { + loading = false; + } } } @@ -198,31 +184,47 @@ {#snippet leftPane()}

Documentation

- {#if loading} -
Loading documentation...
+ {#if loadingDocs} +
Loading...
{:else if error}
{error}
- {:else if docFiles.length > 0} + {:else}
    - {#each docFiles as file} + {#if hasReadme}
  • - {/each} + {/if} + {#if docFiles.length > 0} + {#each docFiles as file} +
  • + +
  • + {/each} + {/if} + {#if !hasReadme && docFiles.length === 0} +
    +

    No documentation files found

    +
    + {/if}
- {:else if documentationContent} -
-

No custom documentation found. Displaying the ReadMe, instead.

-
- {:else} -
-

No documentation files found

-
{/if}
{/snippet} @@ -260,12 +262,14 @@