Browse Source

bug-fixes

master
Silberengel 4 weeks ago
parent
commit
0458665ed7
  1. 96
      .well-known/nostr.json
  2. 74
      internal/asciidoc/processor.go
  3. 9
      internal/generator/html.go
  4. 26
      internal/nostr/feed.go
  5. 1
      internal/server/server.go
  6. BIN
      server
  7. 94
      static/css/main.css
  8. 28
      static/css/responsive.css
  9. 8
      templates/components.html
  10. 126
      templates/contact.html

96
.well-known/nostr.json

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
{
"names": {
"GitCitadel": "846ebf79a0a8813274ec9727490621ad423f16a3e474d7fd66e6a98bfe4e39a4",
"ChipTuner": "036533caa872376946d4e4fdea4c1a0441eda38ca2d9d9417bb36006cbaabf58",
"ChipTunerDev": "011fb1f8cd1cacff53e2e0dc37a688c4dc4363a7c2d59fee16dd98d07601475a",
"buttercat1791": "70122128273bdc07af9be7725fa5c4bc0fc146866bec38d44360dc4bc6cc18b9",
"finrod": "ce1bf9ad92164df227bfcab2813193c60eb4021d35bf4bbbc6fa24c560d0f3e9",
"silberengel": "fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1",
"liminal": "dc4cd086cd7ce5b1832adf4fdd1211289880d2c7e295bcb0e684c01acee77c06",
"TheBeave": "0689df5847a8d3376892da29622d7c0fdc1ef1958f4bc4471d90966aa1eca9f2",
"LibertyGal": "8d34bd2432240c5637174a3db191878baa1c133aec739b64a264259f414be32b",
"testerin": "573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc",
"laeserin": "dd664d5e4016433a8cd69f005ae1480804351789b59de5af06276de65633d319",
"gc-publishing": "3e1ad0f3a5d3c12245db7788546c43ade3d97c6e046c594f6017cd6cd4164690",
"gc-devops": "d05e968d46c61307fae4b18aa5bf1d863b8d14d2e3ba089ed20123deb974b98f",
"nusa" : "d475ce4b3977507130f42c7f86346ef936800f3ae74d5ecf8089280cdc1923e9",
"matt": "fea186c2a4678dbc437704eed2160846e8a781e5fb17056e9bb333840d5bdef2"
},
"relays": {
"846ebf79a0a8813274ec9727490621ad423f16a3e474d7fd66e6a98bfe4e39a4": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"036533caa872376946d4e4fdea4c1a0441eda38ca2d9d9417bb36006cbaabf58": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"011fb1f8cd1cacff53e2e0dc37a688c4dc4363a7c2d59fee16dd98d07601475a": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"70122128273bdc07af9be7725fa5c4bc0fc146866bec38d44360dc4bc6cc18b9": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"ce1bf9ad92164df227bfcab2813193c60eb4021d35bf4bbbc6fa24c560d0f3e9": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"dc4cd086cd7ce5b1832adf4fdd1211289880d2c7e295bcb0e684c01acee77c06": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"0689df5847a8d3376892da29622d7c0fdc1ef1958f4bc4471d90966aa1eca9f2": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"8d34bd2432240c5637174a3db191878baa1c133aec739b64a264259f414be32b": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"dd664d5e4016433a8cd69f005ae1480804351789b59de5af06276de65633d319": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"3e1ad0f3a5d3c12245db7788546c43ade3d97c6e046c594f6017cd6cd4164690": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"d05e968d46c61307fae4b18aa5bf1d863b8d14d2e3ba089ed20123deb974b98f": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"fea186c2a4678dbc437704eed2160846e8a781e5fb17056e9bb333840d5bdef2": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
],
"d475ce4b3977507130f42c7f86346ef936800f3ae74d5ecf8089280cdc1923e9": [
"wss://theforest.nostr1.com",
"wss://thecitadel.nostr1.com",
"wss://nostr.land"
]
}
}

74
internal/asciidoc/processor.go

@ -34,7 +34,10 @@ func (p *Processor) Process(asciidocContent string) (string, error) { @@ -34,7 +34,10 @@ func (p *Processor) Process(asciidocContent string) (string, error) {
// Sanitize HTML to prevent XSS
sanitized := p.sanitizeHTML(html)
return sanitized, nil
// Process links: make external links open in new tab, local links in same tab
processed := p.processLinks(sanitized)
return processed, nil
}
// rewriteLinks rewrites wikilinks and nostr: links in AsciiDoc content
@ -185,3 +188,72 @@ func (p *Processor) sanitizeHTML(html string) string { @@ -185,3 +188,72 @@ func (p *Processor) sanitizeHTML(html string) string {
return html
}
// processLinks processes HTML links to add target="_blank" to external links
// External links are those that start with http:// or https:// and don't point to the linkBaseURL domain
// Local links (including relative links and links to linkBaseURL) open in the same tab
func (p *Processor) processLinks(html string) string {
// Extract domain from linkBaseURL for comparison
linkBaseDomain := ""
if strings.HasPrefix(p.linkBaseURL, "http://") || strings.HasPrefix(p.linkBaseURL, "https://") {
// Extract domain (e.g., "alexandria.gitcitadel.eu" from "https://alexandria.gitcitadel.eu")
parts := strings.Split(strings.TrimPrefix(strings.TrimPrefix(p.linkBaseURL, "https://"), "http://"), "/")
if len(parts) > 0 {
linkBaseDomain = parts[0]
}
}
// Regex to match <a> tags with href attributes (more flexible pattern)
linkRegex := regexp.MustCompile(`<a\s+([^>]*?)href\s*=\s*["']([^"']+)["']([^>]*?)>`)
html = linkRegex.ReplaceAllStringFunc(html, func(match string) string {
// Extract href value
hrefMatch := regexp.MustCompile(`href\s*=\s*["']([^"']+)["']`)
hrefSubmatch := hrefMatch.FindStringSubmatch(match)
if len(hrefSubmatch) < 2 {
return match // No href found, return as-is
}
href := hrefSubmatch[1]
// Check if it's an external link (starts with http:// or https://)
isExternal := strings.HasPrefix(href, "http://") || strings.HasPrefix(href, "https://")
if isExternal {
// Check if it's pointing to our own domain
if linkBaseDomain != "" && strings.Contains(href, linkBaseDomain) {
// Same domain - open in same tab (remove any existing target attribute)
targetRegex := regexp.MustCompile(`\s*target\s*=\s*["'][^"']*["']`)
match = targetRegex.ReplaceAllString(match, "")
return match
}
// External link - add target="_blank" and rel="noopener noreferrer" if not already present
if !strings.Contains(match, `target=`) {
// Insert before the closing >
match = strings.TrimSuffix(match, ">")
if !strings.Contains(match, `rel=`) {
match += ` target="_blank" rel="noopener noreferrer">`
} else {
// Update existing rel attribute to include noopener if not present
relRegex := regexp.MustCompile(`rel\s*=\s*["']([^"']*)["']`)
match = relRegex.ReplaceAllStringFunc(match, func(relMatch string) string {
relValue := relRegex.FindStringSubmatch(relMatch)[1]
if !strings.Contains(relValue, "noopener") {
relValue += " noopener noreferrer"
}
return `rel="` + strings.TrimSpace(relValue) + `"`
})
match += ` target="_blank">`
}
}
} else {
// Local/relative link - ensure it opens in same tab (remove target if present)
targetRegex := regexp.MustCompile(`\s*target\s*=\s*["'][^"']*["']`)
match = targetRegex.ReplaceAllString(match, "")
}
return match
})
return html
}

9
internal/generator/html.go

@ -33,6 +33,14 @@ func getTemplateFuncs() template.FuncMap { @@ -33,6 +33,14 @@ func getTemplateFuncs() template.FuncMap {
"shortenPubkey": func(pubkey string) string {
return nostr.ShortenPubkey(pubkey)
},
"pubkeyToNpub": func(pubkey string) string {
npub, err := nostr.PubkeyToNpub(pubkey)
if err != nil {
// Fallback to hex if conversion fails
return pubkey
}
return npub
},
"truncate": func(s string, maxLen int) string {
if len(s) <= maxLen {
return s
@ -147,6 +155,7 @@ type ArticleItemInfo struct { @@ -147,6 +155,7 @@ type ArticleItemInfo struct {
// FeedItemInfo represents info about a feed item
type FeedItemInfo struct {
EventID string
Author string
Content string
Time string

26
internal/nostr/feed.go

@ -40,29 +40,29 @@ func (fs *FeedService) FetchFeedItems(ctx context.Context, feedRelay string, max @@ -40,29 +40,29 @@ func (fs *FeedService) FetchFeedItems(ctx context.Context, feedRelay string, max
// Convert events to feed items
items := make([]FeedItem, 0, len(result.Events))
for _, event := range result.Events {
item := FeedItem{
item := FeedItem{
EventID: event.ID,
Author: event.PubKey,
Content: event.Content,
Time: time.Unix(int64(event.CreatedAt), 0),
Link: fmt.Sprintf("https://alexandria.gitcitadel.eu/events?id=nevent1%s", event.ID),
}
}
// Extract title, summary, and image tags
// Extract title, summary, and image tags
for _, tag := range event.Tags {
if len(tag) > 0 && len(tag) > 1 {
switch tag[0] {
case "title":
item.Title = tag[1]
case "summary":
item.Summary = tag[1]
case "image":
item.Image = tag[1]
if len(tag) > 0 && len(tag) > 1 {
switch tag[0] {
case "title":
item.Title = tag[1]
case "summary":
item.Summary = tag[1]
case "image":
item.Image = tag[1]
}
}
}
}
items = append(items, item)
items = append(items, item)
}
logger.WithFields(map[string]interface{}{

1
internal/server/server.go

@ -105,6 +105,7 @@ func (s *Server) convertFeedItemsToInfo(items []cache.FeedItem) []generator.Feed @@ -105,6 +105,7 @@ func (s *Server) convertFeedItemsToInfo(items []cache.FeedItem) []generator.Feed
feedItems := make([]generator.FeedItemInfo, 0, len(items))
for _, item := range items {
feedItems = append(feedItems, generator.FeedItemInfo{
EventID: item.EventID,
Author: item.Author,
Content: item.Content,
Time: item.Time.Format("2006-01-02 15:04:05"),

BIN
server

Binary file not shown.

94
static/css/main.css

@ -766,10 +766,18 @@ article { @@ -766,10 +766,18 @@ article {
}
.feed-item {
padding: 1rem 0;
padding: 1.25rem 0;
border-bottom: 1px solid var(--border-color);
overflow-wrap: break-word;
word-wrap: break-word;
transition: background-color 0.2s;
}
.feed-item:hover {
background-color: var(--bg-primary);
margin: 0 -1.5rem;
padding: 1.25rem 1.5rem;
border-radius: 8px;
}
.feed-item:last-child {
@ -780,13 +788,13 @@ article { @@ -780,13 +788,13 @@ article {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
gap: 0.5rem;
gap: 0.75rem;
}
.feed-author {
font-weight: 600;
font-weight: 500;
color: var(--text-primary);
word-break: break-all;
overflow-wrap: anywhere;
@ -794,9 +802,10 @@ article { @@ -794,9 +802,10 @@ article {
}
.feed-content {
color: var(--text-secondary);
margin-bottom: 0.5rem;
font-size: 0.9rem;
color: var(--text-primary);
margin-bottom: 0.75rem;
font-size: 0.95rem;
line-height: 1.6;
overflow-wrap: break-word;
word-wrap: break-word;
}
@ -1118,6 +1127,14 @@ footer { @@ -1118,6 +1127,14 @@ footer {
padding: 1rem;
}
.modal-options .btn,
.modal-options a.btn {
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
.article-title {
font-size: 2.5rem;
margin: 0 0 0.5rem 0;
@ -1529,6 +1546,61 @@ textarea:focus-visible { @@ -1529,6 +1546,61 @@ textarea:focus-visible {
margin-top: 2rem;
}
/* Table of Contents */
.table-of-contents {
margin-top: 2rem;
padding: 1.25rem;
background: var(--bg-secondary);
border-radius: 8px;
border: 1px solid var(--border-color);
font-size: 0.9rem;
}
.table-of-contents h2 {
font-size: 1.1rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
}
.table-of-contents ul {
margin: 0;
padding-left: 1.5rem;
list-style: none;
}
.table-of-contents ul ul {
margin-top: 0.25rem;
padding-left: 1.25rem;
border-left: 1px solid var(--border-color);
}
.table-of-contents ul ul ul {
padding-left: 1rem;
}
.table-of-contents li {
margin-bottom: 0.5rem;
line-height: 1.5;
}
.table-of-contents li:last-child {
margin-bottom: 0;
}
.table-of-contents a {
color: var(--link-color);
text-decoration: none;
word-break: break-word;
display: block;
padding: 0.25rem 0;
}
.table-of-contents a:hover {
text-decoration: underline;
color: var(--link-hover-color);
}
.ebooks-page {
max-width: 1200px;
margin: 0 auto;
@ -1643,6 +1715,14 @@ textarea:focus-visible { @@ -1643,6 +1715,14 @@ textarea:focus-visible {
border-radius: 4px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
text-decoration: none;
color: inherit;
transition: background-color 0.2s, border-color 0.2s;
}
.user-badge:hover {
background: var(--bg-primary);
border-color: var(--link-color);
}
.user-badge-avatar {

28
static/css/responsive.css

@ -508,7 +508,7 @@ @@ -508,7 +508,7 @@
.table-of-contents {
margin-top: 2rem;
padding: 1rem;
padding: 1.25rem;
background: var(--bg-secondary);
border-radius: 8px;
border: 1px solid var(--border-color);
@ -517,25 +517,47 @@ @@ -517,25 +517,47 @@
.table-of-contents h2 {
font-size: 1.1rem;
margin-bottom: 0.75rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
}
.table-of-contents ul {
margin-left: 1rem;
margin: 0;
padding-left: 1.5rem;
list-style: none;
}
.table-of-contents ul ul {
margin-top: 0.25rem;
padding-left: 1.25rem;
border-left: 1px solid var(--border-color);
}
.table-of-contents ul ul ul {
padding-left: 1rem;
}
.table-of-contents li {
margin-bottom: 0.5rem;
line-height: 1.5;
}
.table-of-contents li:last-child {
margin-bottom: 0;
}
.table-of-contents a {
color: var(--link-color);
text-decoration: none;
word-break: break-word;
display: block;
padding: 0.25rem 0;
}
.table-of-contents a:hover {
text-decoration: underline;
color: var(--link-hover-color);
}
/* Feed */

8
templates/components.html

@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
</header>
<div class="feed-content">{{.Content}}</div>
<footer class="feed-footer">
<a href="{{.Link}}" class="feed-link" target="_blank" rel="noopener noreferrer"><span class="icon-inline">{{icon "external-link"}}</span> View on Alexandria</a>
<a href="https://aitherboard.imwald.eu/event/{{.EventID}}" class="feed-link" target="_blank" rel="noopener noreferrer"><span class="icon-inline">{{icon "external-link"}}</span> View on Aitherboard</a>
</footer>
</article>
{{else}}
@ -84,7 +84,9 @@ @@ -84,7 +84,9 @@
{{$pubkey := .Pubkey}}
{{$profiles := .Profiles}}
{{$profile := index $profiles $pubkey}}
<span class="user-badge" title="{{$pubkey}}">
{{$npub := pubkeyToNpub $pubkey}}
{{$profileURL := printf "https://alexandria.gitcitadel.eu/events?id=%s" $npub}}
<a href="{{$profileURL}}" class="user-badge" title="{{$pubkey}}" target="_blank" rel="noopener noreferrer">
{{if and $profile $profile.Picture}}
<img src="{{$profile.Picture}}" alt="{{if $profile.DisplayName}}{{$profile.DisplayName}}{{else if $profile.Name}}{{$profile.Name}}{{else}}User{{end}}" class="user-badge-avatar" loading="lazy">
{{else}}
@ -102,7 +104,7 @@ @@ -102,7 +104,7 @@
{{if and $profile $profile.Name (not $profile.DisplayName)}}
<span class="user-badge-handle">@{{$profile.Name}}</span>
{{end}}
</span>
</a>
{{end}}
{{/* Mobile Custom Dropdown Component - Shows title and profile pic

126
templates/contact.html

@ -15,6 +15,11 @@ @@ -15,6 +15,11 @@
<span class="icon-inline">{{icon "github"}}</span> GitHub: ShadowySupercode
</a>
</li>
<li>
<a href="https://alexandria.gitcitadel.eu/events?id=npub1m3xdppkd0njmrqe2ma8a6ys39zvgp5k8u22mev8xsnqp4nh80srqhqa5sf" target="_blank" rel="noopener noreferrer">
<span class="icon-inline">{{icon "user"}}</span> GitCitadel on Alexandria
</a>
</li>
</ul>
</div>
@ -121,6 +126,45 @@ @@ -121,6 +126,45 @@
</div>
</div>
<!-- Success Modal -->
<div id="success-modal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2><span class="icon-inline">{{icon "check-circle"}}</span> Success!</h2>
<button type="button" class="modal-close" id="success-modal-close-btn" aria-label="Close">&times;</button>
</div>
<div class="modal-body">
<p>Your message has been successfully submitted to the Nostr relays.</p>
<div class="modal-options">
<a href="https://aitherboard.imwald.eu/repos/naddr1qvzqqqrhnypzplfq3m5v3u5r0q9f255fdeyz8nyac6lagssx8zy4wugxjs8ajf7pqq9xw6t5vd5hgctyv4kqde47kt?tab=issues" target="_blank" rel="noopener noreferrer" class="btn btn-primary">
<span class="icon-inline">{{icon "external-link"}}</span> View Issue Board
</a>
<button type="button" id="success-modal-close-btn2" class="btn btn-secondary">
<span class="icon-inline">{{icon "x"}}</span> Close
</button>
</div>
</div>
</div>
</div>
<!-- Failure Modal -->
<div id="failure-modal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2><span class="icon-inline">{{icon "alert-circle"}}</span> Submission Failed</h2>
<button type="button" class="modal-close" id="failure-modal-close-btn" aria-label="Close">&times;</button>
</div>
<div class="modal-body">
<p id="failure-message">Failed to publish your message to any of the configured relays. Please try again later.</p>
<div class="modal-options">
<button type="button" id="failure-modal-close-btn2" class="btn btn-primary">
<span class="icon-inline">{{icon "x"}}</span> Close
</button>
</div>
</div>
</div>
</div>
{{if .RepoAnnouncement}}
<script type="application/json" id="repo-announcement-data">{{json .RepoAnnouncement}}</script>
{{end}}
@ -137,6 +181,13 @@ @@ -137,6 +181,13 @@
const modalCloseBtn = document.getElementById('modal-close-btn');
const loginBtn = document.getElementById('login-btn');
const anonymousBtn = document.getElementById('anonymous-btn');
const successModal = document.getElementById('success-modal');
const successModalCloseBtn = document.getElementById('success-modal-close-btn');
const successModalCloseBtn2 = document.getElementById('success-modal-close-btn2');
const failureModal = document.getElementById('failure-modal');
const failureModalCloseBtn = document.getElementById('failure-modal-close-btn');
const failureModalCloseBtn2 = document.getElementById('failure-modal-close-btn2');
const failureMessage = document.getElementById('failure-message');
// Get contact relays from JSON script tag
let contactRelays = [];
@ -183,6 +234,31 @@ @@ -183,6 +234,31 @@
modal.style.display = 'none';
}
function showSuccessModal() {
successModal.style.display = 'flex';
}
function hideSuccessModal() {
successModal.style.display = 'none';
// Reset form
form.reset();
submitBtn.disabled = false;
submitBtn.innerHTML = '<span class="icon-inline"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg></span> Submit';
}
function showFailureModal(errorMessage) {
if (errorMessage) {
failureMessage.textContent = errorMessage;
}
failureModal.style.display = 'flex';
}
function hideFailureModal() {
failureModal.style.display = 'none';
submitBtn.disabled = false;
submitBtn.innerHTML = '<span class="icon-inline"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg></span> Submit';
}
// Close modal handlers
modalCloseBtn.addEventListener('click', hideModal);
modal.addEventListener('click', function(e) {
@ -191,6 +267,22 @@ @@ -191,6 +267,22 @@
}
});
successModalCloseBtn.addEventListener('click', hideSuccessModal);
successModalCloseBtn2.addEventListener('click', hideSuccessModal);
successModal.addEventListener('click', function(e) {
if (e.target === successModal) {
hideSuccessModal();
}
});
failureModalCloseBtn.addEventListener('click', hideFailureModal);
failureModalCloseBtn2.addEventListener('click', hideFailureModal);
failureModal.addEventListener('click', function(e) {
if (e.target === failureModal) {
hideFailureModal();
}
});
// Generate key pair for anonymous submission
async function generateKeyPair() {
const keyPair = NostrTools.generatePrivateKey();
@ -218,14 +310,16 @@ @@ -218,14 +310,16 @@
const result = await response.json();
if (response.ok && result.success) {
window.location.href = '/contact?success=true&event_id=' + result.event_id;
} else {
showStatus('Failed to publish: ' + (result.error || 'Unknown error'), true);
submitBtn.disabled = false;
// Show success modal
submitBtn.innerHTML = '<span class="icon-inline"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg></span> Submit';
showSuccessModal();
} else {
// Show failure modal
const errorMsg = 'Failed to publish your message to any of the configured relays. ' + (result.error || 'Please try again later.');
showFailureModal(errorMsg);
}
}
}
// Process submission with pubkey
async function processSubmission(useExtension) {
hideModal();
@ -268,14 +362,14 @@ @@ -268,14 +362,14 @@
// Add 'a' tag for repository announcement if available
if (repoAnnouncement) {
tags.push(['a', `30617:${repoAnnouncement.pubkey}:${repoAnnouncement.dTag}`]);
tags.push(['p', repoAnnouncement.pubkey]);
if (repoAnnouncement.maintainers && repoAnnouncement.maintainers.length > 0) {
repoAnnouncement.maintainers.forEach(maintainer => {
tags.push(['p', maintainer]);
});
}
tags.push(['a', `30617:${repoAnnouncement.pubkey}:${repoAnnouncement.dTag}`]);
tags.push(['p', repoAnnouncement.pubkey]);
if (repoAnnouncement.maintainers && repoAnnouncement.maintainers.length > 0) {
repoAnnouncement.maintainers.forEach(maintainer => {
tags.push(['p', maintainer]);
});
}
}
// Add required 'p' tags for contact recipients
@ -317,9 +411,7 @@ @@ -317,9 +411,7 @@
await submitEvent(signedEvent);
} catch (error) {
console.error('Error:', error);
showStatus('Error: ' + error.message, true);
submitBtn.disabled = false;
submitBtn.innerHTML = '<span class="icon-inline"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg></span> Submit';
showFailureModal('Error: ' + error.message);
}
}

Loading…
Cancel
Save