8 changed files with 277 additions and 106 deletions
@ -1,74 +1,59 @@ |
|||||||
import { Controller } from '@hotwired/stimulus'; |
import { Controller } from '@hotwired/stimulus'; |
||||||
|
|
||||||
|
const LOADING_HTML = `<div class="nostr-preview__loading text-center my-2"><span class="nostr-preview__spinner" role="status" aria-label="Loading"></span><span class="nostr-preview__loading-text ms-2">Loading preview…</span></div>`; |
||||||
|
const UNAVAILABLE_HTML = `<div class="alert alert-warning my-2" role="status">Preview unavailable.</div>`; |
||||||
|
|
||||||
export default class extends Controller { |
export default class extends Controller { |
||||||
static values = { |
static values = { |
||||||
identifier: String, |
identifier: String, |
||||||
type: String, |
type: String, |
||||||
decoded: String, |
decoded: String, |
||||||
fullMatch: String |
fullMatch: String, |
||||||
} |
}; |
||||||
|
|
||||||
static targets = ['container'] |
static targets = ['container']; |
||||||
|
|
||||||
async connect() { |
connect() { |
||||||
await this.fetchPreview(); |
this.fetchPreview(); |
||||||
} |
} |
||||||
|
|
||||||
async fetchPreview() { |
async fetchPreview() { |
||||||
|
if (!this.hasContainerTarget) { |
||||||
|
return; |
||||||
|
} |
||||||
|
this.containerTarget.innerHTML = LOADING_HTML; |
||||||
try { |
try { |
||||||
this.containerTarget.innerHTML = '<div class="nostr-preview__loading text-center my-2"><span class="nostr-preview__spinner" role="status" aria-label="Loading"></span><span class="nostr-preview__loading-text ms-2">Loading preview…</span></div>'; |
|
||||||
if (this.typeValue === 'url' && this.fullMatchValue) { |
if (this.typeValue === 'url' && this.fullMatchValue) { |
||||||
// Fetch OG preview for plain URLs
|
const res = await fetch('/og-preview/', { |
||||||
fetch("/og-preview/", { |
method: 'POST', |
||||||
method: "POST", |
headers: { 'Content-Type': 'application/json' }, |
||||||
headers: { |
body: JSON.stringify({ url: this.fullMatchValue }), |
||||||
"Content-Type": "application/json" |
}); |
||||||
}, |
|
||||||
body: JSON.stringify({ url: this.fullMatchValue }) |
|
||||||
}) |
|
||||||
.then(res => { |
|
||||||
if (!res.ok) { |
if (!res.ok) { |
||||||
throw new Error(`HTTP error! status: ${res.status}`); |
throw new Error(`HTTP ${res.status}`); |
||||||
} |
} |
||||||
return res.text(); |
this.containerTarget.innerHTML = await res.text(); |
||||||
}) |
return; |
||||||
.then(data => { |
} |
||||||
this.containerTarget.innerHTML = data; |
const res = await fetch('/preview/', { |
||||||
}) |
method: 'POST', |
||||||
.catch(error => { |
headers: { 'Content-Type': 'application/json' }, |
||||||
console.error("Error:", error); |
body: JSON.stringify({ |
||||||
this.containerTarget.innerHTML = `<div class="alert alert-warning">Unable to load OG preview for ${this.fullMatchValue}</div>`; |
|
||||||
}); |
|
||||||
} else { |
|
||||||
// Fallback to Nostr preview
|
|
||||||
const data = { |
|
||||||
identifier: this.identifierValue, |
identifier: this.identifierValue, |
||||||
type: this.typeValue, |
type: this.typeValue, |
||||||
decoded: this.decodedValue |
decoded: this.decodedValue, |
||||||
}; |
}), |
||||||
fetch("/preview/", { |
|
||||||
method: "POST", |
|
||||||
headers: { |
|
||||||
"Content-Type": "application/json" |
|
||||||
}, |
|
||||||
body: JSON.stringify(data) |
|
||||||
}) |
|
||||||
.then(res => { |
|
||||||
if (!res.ok) { |
|
||||||
throw new Error(`HTTP error! status: ${res.status}`); |
|
||||||
} |
|
||||||
return res.text(); |
|
||||||
}) |
|
||||||
.then(data => { |
|
||||||
this.containerTarget.innerHTML = data; |
|
||||||
}) |
|
||||||
.catch(error => { |
|
||||||
console.error("Error:", error); |
|
||||||
}); |
}); |
||||||
} |
if (!res.ok) { |
||||||
} catch (error) { |
throw new Error(`HTTP ${res.status}`); |
||||||
console.error('Error fetching Nostr preview:', error); |
} |
||||||
this.containerTarget.innerHTML = `<div class="alert alert-warning">Unable to load preview for ${this.fullMatchValue}</div>`; |
this.containerTarget.innerHTML = await res.text(); |
||||||
|
} catch (e) { |
||||||
|
// NetworkError / offline: avoid console.error noise; one inline fallback per block
|
||||||
|
console.debug('nostr_preview: fetch failed', e); |
||||||
|
this.containerTarget.innerHTML = this.typeValue === 'url' && this.fullMatchValue |
||||||
|
? `<div class="alert alert-warning my-2" role="status">Unable to load link preview for ${this.fullMatchValue}.</div>` |
||||||
|
: UNAVAILABLE_HTML; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
Loading…
Reference in new issue