Browse Source

bug-fixes

master
Silberengel 4 weeks ago
parent
commit
b7d344363d
  1. 20
      src/lib/components/modals/EventJsonModal.svelte
  2. 838
      src/lib/components/write/CreateEventForm.svelte
  3. 19
      src/lib/services/content/git-repo-fetcher.ts
  4. 4
      src/routes/api/gitea-proxy/[...path]/+server.ts
  5. 10
      src/routes/repos/[naddr]/+page.svelte
  6. 106
      src/routes/write/+page.svelte
  7. 4
      static/healthz.json

20
src/lib/components/modals/EventJsonModal.svelte

@ -140,6 +140,7 @@ @@ -140,6 +140,7 @@
display: flex;
flex-direction: column;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
margin: 0 auto; /* Center the modal */
}
@media (max-width: 768px) {
@ -278,6 +279,8 @@ @@ -278,6 +279,8 @@
overflow-x: auto;
max-height: 60vh;
white-space: pre;
text-align: left; /* Ensure text aligns left */
position: relative; /* Ensure proper stacking context */
}
.json-preview.word-wrap {
@ -291,12 +294,13 @@ @@ -291,12 +294,13 @@
.json-preview code {
display: block;
padding: 0;
background: transparent !important;
background: #000000 !important; /* Match parent background to prevent any bleed-through */
/* Colors are defined by highlight.js vs2015 theme */
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Droid Sans Mono', 'Source Code Pro', monospace;
font-size: 0.875rem;
line-height: 1.5;
white-space: pre;
position: relative; /* Ensure proper stacking */
}
.json-preview.word-wrap code {
@ -316,6 +320,20 @@ @@ -316,6 +320,20 @@
overflow-wrap: break-word !important;
}
/* Ensure highlight.js doesn't override the background */
.json-preview :global(code.hljs),
.json-preview :global(.hljs) {
background: #000000 !important;
padding: 0 !important;
margin: 0 !important;
}
/* Override any highlight.js theme backgrounds that might be causing the offset */
.json-preview :global(.hljs *),
.json-preview :global(code.hljs *) {
background: transparent !important;
}
@media (max-width: 768px) {
.json-preview {
padding: 0.75rem;

838
src/lib/components/write/CreateEventForm.svelte

File diff suppressed because it is too large Load Diff

19
src/lib/services/content/git-repo-fetcher.ts

@ -45,10 +45,24 @@ export interface GitFile { @@ -45,10 +45,24 @@ export interface GitFile {
size?: number;
}
/**
* Check if a URL is a GRASP (Git Repository Access via Secure Protocol) URL
* GRASP URLs contain npub (Nostr public key) in the path: https://host/npub.../repo.git
*/
function isGraspUrl(url: string): boolean {
// GRASP URLs have npub (starts with npub1) in the path
return /\/npub1[a-z0-9]+/i.test(url);
}
/**
* Parse git URL to extract platform, owner, and repo
*/
function parseGitUrl(url: string): { platform: string; owner: string; repo: string; baseUrl: string } | null {
// Skip GRASP URLs - they don't use standard git hosting APIs
if (isGraspUrl(url)) {
return null;
}
// GitHub
const githubMatch = url.match(/github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
if (githubMatch) {
@ -89,8 +103,13 @@ function parseGitUrl(url: string): { platform: string; owner: string; repo: stri @@ -89,8 +103,13 @@ function parseGitUrl(url: string): { platform: string; owner: string; repo: stri
// Gitea and other Git hosting services (generic pattern) - matches https://host/owner/repo.git or https://host/owner/repo
// This is a catch-all for services that use Gitea-compatible API (like Gitea, Forgejo, etc.)
// But skip if it looks like a GRASP URL (has npub in path)
const giteaMatch = url.match(/(https?:\/\/[^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
if (giteaMatch) {
// Double-check it's not a GRASP URL (npub in owner position)
if (giteaMatch[2].startsWith('npub1')) {
return null;
}
return {
platform: 'gitea',
owner: giteaMatch[2],

4
src/routes/api/gitea-proxy/[...path]/+server.ts

@ -320,9 +320,9 @@ export const GET: RequestHandler = async ({ params, url }) => { @@ -320,9 +320,9 @@ export const GET: RequestHandler = async ({ params, url }) => {
});
} else {
// Log non-404 errors
console.error('[Gitea Proxy] Error response:', response.status, response.statusText);
console.error('[Gitea Proxy] Error response:', response.status, response.statusText);
console.error('[Gitea Proxy] Request URL:', targetUrl);
console.error('[Gitea Proxy] Response body:', body.substring(0, 500));
console.error('[Gitea Proxy] Response body:', body.substring(0, 500));
}
}

10
src/routes/repos/[naddr]/+page.svelte

@ -1234,6 +1234,11 @@ @@ -1234,6 +1234,11 @@
<div class="readme-container">
{@html renderReadme(gitRepo.readme.content, gitRepo.readme.format)}
</div>
{:else if gitRepoFetchAttempted && !loadingGitRepo && extractGitUrls(repoEvent).some(url => /\/npub1[a-z0-9]+/i.test(url))}
<div class="empty-state">
<p class="text-fog-text dark:text-fog-dark-text">GRASP (Git Repository Access via Secure Protocol) repositories are not yet supported for fetching README files.</p>
<p class="text-fog-text-light dark:text-fog-dark-text-light mt-2">The repository description is shown in the header above.</p>
</div>
{:else}
<div class="empty-state">
<p class="text-fog-text dark:text-fog-dark-text">No README found.</p>
@ -1295,6 +1300,11 @@ @@ -1295,6 +1300,11 @@
</div>
{/if}
</div>
{:else if gitRepoFetchAttempted && !loadingGitRepo && extractGitUrls(repoEvent).some(url => /\/npub1[a-z0-9]+/i.test(url))}
<div class="empty-state">
<p class="text-fog-text dark:text-fog-dark-text">GRASP (Git Repository Access via Secure Protocol) repositories are not yet supported for fetching repository data.</p>
<p class="text-fog-text-light dark:text-fog-dark-text-light mt-2">GRASP uses a different protocol than standard git hosting services and cannot be accessed via their APIs.</p>
</div>
{:else}
<div class="empty-state">
<p class="text-fog-text dark:text-fog-dark-text">Git repository data not available.</p>

106
src/routes/write/+page.svelte

@ -6,22 +6,80 @@ @@ -6,22 +6,80 @@
import { onMount } from 'svelte';
import { page } from '$app/stores';
import type { NostrEvent } from '../../lib/types/nostr.js';
// Read kind from URL synchronously so it's available on first render
const kindParam = $derived($page.url.searchParams.get('kind'));
let initialKind = $state<number | null>(null);
let initialEvent = $state<NostrEvent | null>(null);
let isCloneMode = $state(false);
// Read from sessionStorage synchronously (runs immediately, not in onMount)
// This ensures initialEvent is set before CreateEventForm renders
if (typeof window !== 'undefined') {
// Check for clone/edit event data in sessionStorage (takes priority)
const cloneDataStr = sessionStorage.getItem('aitherboard_cloneEvent');
if (cloneDataStr) {
try {
const cloneData = JSON.parse(cloneDataStr);
// Construct event from clone data
// Use nullish coalescing to properly handle kind 0
initialEvent = {
id: '',
pubkey: '',
created_at: Math.floor(Date.now() / 1000),
kind: cloneData.kind !== undefined && cloneData.kind !== null ? cloneData.kind : 1,
content: cloneData.content || '',
tags: cloneData.tags || [],
sig: ''
};
isCloneMode = cloneData.isClone === true;
// Clear sessionStorage after reading
sessionStorage.removeItem('aitherboard_cloneEvent');
} catch (error) {
console.error('Error parsing clone event data:', error);
}
} else {
// Check for highlight data in sessionStorage (fallback)
const highlightDataStr = sessionStorage.getItem('aitherboard_highlightData');
if (highlightDataStr) {
try {
const highlightData = JSON.parse(highlightDataStr);
// Construct event from highlight data (default to kind 1)
initialEvent = {
id: '',
pubkey: '',
created_at: Math.floor(Date.now() / 1000),
kind: 1,
content: highlightData.content || '',
tags: highlightData.tags || [],
sig: ''
};
// Clear sessionStorage after reading
sessionStorage.removeItem('aitherboard_highlightData');
} catch (error) {
console.error('Error parsing highlight data:', error);
}
}
}
}
// Set initial kind from URL if available
// Set initial kind from URL if available (only if no event from sessionStorage)
$effect(() => {
if (kindParam) {
if (kindParam && !initialEvent) {
const kind = parseInt(kindParam, 10);
if (!isNaN(kind)) {
initialKind = kind;
initialEvent = {
id: '',
pubkey: '',
created_at: Math.floor(Date.now() / 1000),
kind: kind,
content: '',
tags: [],
sig: ''
};
}
}
});
let initialContent = $state<string | null>(null);
let initialTags = $state<string[][] | null>(null);
let isCloneMode = $state(false);
// Subscribe to session changes to reactively update login status
let currentSession = $state(sessionManager.session.value);
@ -46,36 +104,6 @@ @@ -46,36 +104,6 @@
console.error('Failed to restore session in write page:', error);
}
}
// Check for clone/edit event data in sessionStorage (takes priority)
const cloneDataStr = sessionStorage.getItem('aitherboard_cloneEvent');
if (cloneDataStr) {
try {
const cloneData = JSON.parse(cloneDataStr);
initialKind = cloneData.kind || null;
initialContent = cloneData.content || null;
initialTags = cloneData.tags || null;
isCloneMode = cloneData.isClone === true;
// Clear sessionStorage after reading
sessionStorage.removeItem('aitherboard_cloneEvent');
} catch (error) {
console.error('Error parsing clone event data:', error);
}
} else {
// Check for highlight data in sessionStorage (fallback)
const highlightDataStr = sessionStorage.getItem('aitherboard_highlightData');
if (highlightDataStr) {
try {
const highlightData = JSON.parse(highlightDataStr);
initialContent = highlightData.content || null;
initialTags = highlightData.tags || null;
// Clear sessionStorage after reading
sessionStorage.removeItem('aitherboard_highlightData');
} catch (error) {
console.error('Error parsing highlight data:', error);
}
}
}
});
</script>
@ -95,9 +123,7 @@ @@ -95,9 +123,7 @@
{:else}
<div class="form-container">
<CreateEventForm
initialKind={initialKind}
initialContent={initialContent}
initialTags={initialTags}
initialEvent={initialEvent}
/>
</div>
{/if}

4
static/healthz.json

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
"status": "ok",
"service": "aitherboard",
"version": "0.3.2",
"buildTime": "2026-02-14T09:16:17.577Z",
"buildTime": "2026-02-14T16:25:59.663Z",
"gitCommit": "unknown",
"timestamp": 1771060577577
"timestamp": 1771086359663
}
Loading…
Cancel
Save