forked from mleku/next.orly.dev
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3e3af08644
|
|||
|
fbdf565bf7
|
|||
|
14b6960070
|
|||
|
f9896e52ea
|
|||
|
ad7ca69964
|
|||
|
facf03783f
|
117
app/server.go
117
app/server.go
@@ -18,7 +18,9 @@ import (
|
||||
"next.orly.dev/pkg/acl"
|
||||
"next.orly.dev/pkg/database"
|
||||
"next.orly.dev/pkg/encoders/event"
|
||||
"next.orly.dev/pkg/encoders/filter"
|
||||
"next.orly.dev/pkg/encoders/hex"
|
||||
"next.orly.dev/pkg/encoders/tag"
|
||||
"next.orly.dev/pkg/protocol/auth"
|
||||
"next.orly.dev/pkg/protocol/publish"
|
||||
)
|
||||
@@ -160,6 +162,8 @@ func (s *Server) UserInterface() {
|
||||
// Export endpoints
|
||||
s.mux.HandleFunc("/api/export", s.handleExport)
|
||||
s.mux.HandleFunc("/api/export/mine", s.handleExportMine)
|
||||
// Events endpoints
|
||||
s.mux.HandleFunc("/api/events/mine", s.handleEventsMine)
|
||||
// Import endpoint (admin only)
|
||||
s.mux.HandleFunc("/api/import", s.handleImport)
|
||||
}
|
||||
@@ -478,10 +482,121 @@ func (s *Server) handleImport(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "Empty request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
s.D.Import(r.Body)
|
||||
s.D.Import(r.Body)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
w.Write([]byte(`{"success": true, "message": "Import started"}`))
|
||||
}
|
||||
|
||||
// handleEventsMine returns the authenticated user's events in JSON format with pagination
|
||||
func (s *Server) handleEventsMine(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Require auth cookie
|
||||
c, err := r.Cookie("orly_auth")
|
||||
if err != nil || c.Value == "" {
|
||||
http.Error(w, "Not authenticated", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
pubkey, err := hex.Dec(c.Value)
|
||||
if chk.E(err) {
|
||||
http.Error(w, "Invalid auth cookie", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse pagination parameters
|
||||
query := r.URL.Query()
|
||||
limit := 50 // default limit
|
||||
if l := query.Get("limit"); l != "" {
|
||||
if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 && parsed <= 100 {
|
||||
limit = parsed
|
||||
}
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if o := query.Get("offset"); o != "" {
|
||||
if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
|
||||
offset = parsed
|
||||
}
|
||||
}
|
||||
|
||||
// Use QueryEvents with filter for this user's events
|
||||
f := &filter.F{
|
||||
Authors: tag.NewFromBytesSlice(pubkey),
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: Querying events for pubkey: %s", hex.Enc(pubkey))
|
||||
events, err := s.D.QueryEvents(s.Ctx, f)
|
||||
if chk.E(err) {
|
||||
log.Printf("DEBUG: QueryEvents failed: %v", err)
|
||||
http.Error(w, "Failed to query events", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("DEBUG: QueryEvents returned %d events", len(events))
|
||||
|
||||
// If no events found, let's also check if there are any events at all in the database
|
||||
if len(events) == 0 {
|
||||
// Create a filter to get any events (no authors filter)
|
||||
allEventsFilter := &filter.F{}
|
||||
allEvents, err := s.D.QueryEvents(s.Ctx, allEventsFilter)
|
||||
if err == nil {
|
||||
log.Printf("DEBUG: Total events in database: %d", len(allEvents))
|
||||
} else {
|
||||
log.Printf("DEBUG: Failed to query all events: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Events are already sorted by QueryEvents in reverse chronological order
|
||||
|
||||
// Apply offset and limit manually since QueryEvents doesn't support offset
|
||||
totalEvents := len(events)
|
||||
start := offset
|
||||
if start > totalEvents {
|
||||
start = totalEvents
|
||||
}
|
||||
end := start + limit
|
||||
if end > totalEvents {
|
||||
end = totalEvents
|
||||
}
|
||||
|
||||
paginatedEvents := events[start:end]
|
||||
|
||||
// Convert events to JSON response format
|
||||
type EventResponse struct {
|
||||
ID string `json:"id"`
|
||||
Kind int `json:"kind"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Content string `json:"content"`
|
||||
RawJSON string `json:"raw_json"`
|
||||
}
|
||||
|
||||
response := struct {
|
||||
Events []EventResponse `json:"events"`
|
||||
Total int `json:"total"`
|
||||
Offset int `json:"offset"`
|
||||
Limit int `json:"limit"`
|
||||
}{
|
||||
Events: make([]EventResponse, len(paginatedEvents)),
|
||||
Total: totalEvents,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
}
|
||||
|
||||
for i, ev := range paginatedEvents {
|
||||
response.Events[i] = EventResponse{
|
||||
ID: hex.Enc(ev.ID),
|
||||
Kind: int(ev.Kind),
|
||||
CreatedAt: int64(ev.CreatedAt),
|
||||
Content: string(ev.Content),
|
||||
RawJSON: string(ev.Serialize()),
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
1
app/web/dist/index-q4cwd1fy.css
vendored
Normal file
1
app/web/dist/index-q4cwd1fy.css
vendored
Normal file
File diff suppressed because one or more lines are too long
160
app/web/dist/index-tha189jf.js
vendored
Normal file
160
app/web/dist/index-tha189jf.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
app/web/dist/index-zhtd763e.css
vendored
1
app/web/dist/index-zhtd763e.css
vendored
@@ -1 +0,0 @@
|
||||
*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}html,body,#root{height:100%}html{-webkit-text-size-adjust:100%;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Helvetica,Arial,"\"Apple Color Emoji\"","\"Segoe UI Emoji\"";line-height:1.5}body{margin:0}button,input{font:inherit;color:inherit}img{display:block;max-width:100%;height:auto}.sticky{position:sticky}.relative{position:relative}.absolute{position:absolute}.top-0{top:0}.left-0{left:0}.inset-0{inset:0}.z-50{z-index:50}.z-10{z-index:10}.block{display:block}.flex{display:flex}.items-center{align-items: center}.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.flex-grow{flex-grow:1}.shrink-0{flex-shrink:0}.overflow-hidden{overflow:hidden}.w-full{width:100%}.w-auto{width:auto}.w-16{width:4rem}.h-full{height:100%}.h-16{height:4rem}.aspect-square{aspect-ratio:1}.max-w-3xl{max-width:48rem}.p-0{padding:0}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-6{padding:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.mr-0{margin-right:0}.mr-2{margin-right:.5rem}.mt-2{margin-top:.5rem}.mt-5{margin-top:1.25rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border-0{border-width:0}.border-2{border-width:2px}.border-white{border-color:#fff}.border{border-width:1px}.border-gray-300{border-color:#d1d5db}.bg-white{background-color:#fff}.bg-gray-100{background-color:#f3f4f6}.bg-blue-600{background-color:#2563eb}.hover\:bg-blue-700:hover{background-color:#1d4ed8}.bg-red-600{background-color:#dc2626}.hover\:bg-red-700:hover{background-color:#b91c1c}.bg-cyan-100{background-color:#cffafe}.bg-green-100{background-color:#d1fae5}.bg-red-100{background-color:#fee2e2}.bg-cover{background-size:cover}.bg-center{background-position:50%}.bg-transparent{background-color:#0000}.text-left{text-align:left}.text-white{color:#fff}.text-gray-500{color:#6b7280}.hover\:text-gray-800:hover{color:#1f2937}.text-green-800{color:#065f46}.text-red-800{color:#991b1b}.text-cyan-800{color:#155e75}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.font-bold{font-weight:700}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;box-shadow:var(--tw-shadow)}.cursor-pointer{cursor:pointer}.box-border{box-sizing:border-box}.hover\:bg-transparent:hover{background-color:#0000}body{margin:0;padding:0;font-family:Arial,sans-serif}.container{background:#f9f9f9;border-radius:8px;margin-top:20px;padding:30px}.form-group{margin-bottom:20px}label{display:block;margin-bottom:5px;font-weight:700}input,textarea{border:1px solid #ddd;border-radius:4px;width:100%;padding:10px}button{color:#fff;cursor:pointer;background:#007cba;border:none;border-radius:4px;padding:12px 20px}button:hover{background:#005a87}.danger-button{background:#dc3545}.danger-button:hover{background:#c82333}.status{border-radius:4px;margin-top:20px;margin-bottom:20px;padding:10px}.success{color:#155724;background:#d4edda}.error{color:#721c24;background:#f8d7da}.info{color:#0c5460;background:#d1ecf1}.header-panel{position:sticky;z-index:1000;display:flex;overflow:hidden;background-color:#f8f9fa;background-position:50%;background-size:cover;align-items: center;width:100%;height:60px;top:0;left:0;box-shadow:0 2px 4px #0000001a}.header-content{display:flex;box-sizing:border-box;align-items: center;width:100%;height:100%;margin:0 auto;padding:0 0 0 12px}.header-left{display:flex;justify-content:flex-start;align-items: center;height:100%}.header-center{display:flex;position:relative;overflow:hidden;flex-grow:1;justify-content:flex-start;align-items: center}.header-right{display:flex;justify-content:flex-end;align-items: center;height:100%}.header-logo{aspect-ratio:1;object-fit:cover;border-radius:0;flex-shrink:0;width:auto;height:100%}.user-avatar{object-fit:cover;border:2px solid #fff;border-radius:50%;width:40px;height:40px;margin-right:10px;box-shadow:0 1px 3px #0003}.user-profile{display:flex;position:relative;z-index:1;align-items: center}.user-info{text-align:left;font-size:1.2em;font-weight:700}.user-name{display:block;font-size:1em;font-weight:700}.profile-banner{position:absolute;z-index:-1;opacity:.7;width:100%;height:100%;top:0;left:0}.logout-button{color:#6c757d;cursor:pointer;display:flex;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items: center;width:48px;height:100%;margin-left:10px;margin-right:0;padding:0;font-size:20px}.logout-button:hover{color:#343a40;background:0 0}
|
||||
160
app/web/dist/index-zqddcpy5.js
vendored
160
app/web/dist/index-zqddcpy5.js
vendored
File diff suppressed because one or more lines are too long
21
app/web/dist/index.html
vendored
21
app/web/dist/index.html
vendored
@@ -5,8 +5,25 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Nostr Relay</title>
|
||||
|
||||
<link rel="stylesheet" crossorigin href="./index-zhtd763e.css"><script type="module" crossorigin src="./index-zqddcpy5.js"></script></head>
|
||||
<body class="bg-white">
|
||||
<link rel="stylesheet" crossorigin href="./index-q4cwd1fy.css"><script type="module" crossorigin src="./index-tha189jf.js"></script></head>
|
||||
<body>
|
||||
<script>
|
||||
// Apply system theme preference immediately to avoid flash of wrong theme
|
||||
function applyTheme(isDark) {
|
||||
document.body.classList.remove('bg-white', 'bg-gray-900');
|
||||
document.body.classList.add(isDark ? 'bg-gray-900' : 'bg-white');
|
||||
}
|
||||
|
||||
// Set initial theme
|
||||
applyTheme(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
|
||||
// Listen for theme changes
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
||||
applyTheme(e.matches);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<div id="root"></div>
|
||||
|
||||
</body>
|
||||
|
||||
32
app/web/dist/tailwind.min.css
vendored
32
app/web/dist/tailwind.min.css
vendored
@@ -39,26 +39,49 @@ img{display:block;max-width:100%;height:auto}
|
||||
.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}
|
||||
.border-0{border-width:0}.border-2{border-width:2px}
|
||||
.border-white{border-color:#fff}
|
||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}
|
||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}.border-gray-600{border-color:#4b5563}
|
||||
.border-red-500{border-color:#ef4444}.border-red-700{border-color:#b91c1c}
|
||||
|
||||
/* Colors / Backgrounds */
|
||||
.bg-white{background-color:#fff}
|
||||
.bg-gray-100{background-color:#f3f4f6}
|
||||
.bg-gray-200{background-color:#e5e7eb}
|
||||
.bg-gray-300{background-color:#d1d5db}
|
||||
.bg-gray-600{background-color:#4b5563}
|
||||
.bg-gray-700{background-color:#374151}
|
||||
.bg-gray-800{background-color:#1f2937}
|
||||
.bg-gray-900{background-color:#111827}
|
||||
.bg-blue-500{background-color:#3b82f6}
|
||||
.bg-blue-600{background-color:#2563eb}.hover\:bg-blue-700:hover{background-color:#1d4ed8}
|
||||
.hover\:bg-blue-600:hover{background-color:#2563eb}
|
||||
.bg-red-600{background-color:#dc2626}.hover\:bg-red-700:hover{background-color:#b91c1c}
|
||||
.bg-cyan-100{background-color:#cffafe}
|
||||
.bg-green-100{background-color:#d1fae5}
|
||||
.bg-red-100{background-color:#fee2e2}
|
||||
.bg-red-50{background-color:#fef2f2}
|
||||
.bg-green-900{background-color:#064e3b}
|
||||
.bg-red-900{background-color:#7f1d1d}
|
||||
.bg-cyan-900{background-color:#164e63}
|
||||
.bg-cover{background-size:cover}.bg-center{background-position:center}
|
||||
.bg-transparent{background-color:transparent}
|
||||
|
||||
/* Text */
|
||||
.text-left{text-align:left}
|
||||
.text-white{color:#fff}
|
||||
.text-gray-300{color:#d1d5db}
|
||||
.text-gray-500{color:#6b7280}.hover\:text-gray-800:hover{color:#1f2937}
|
||||
.hover\:text-gray-100:hover{color:#f3f4f6}
|
||||
.text-gray-700{color:#374151}
|
||||
.text-gray-800{color:#1f2937}
|
||||
.text-gray-900{color:#111827}
|
||||
.text-gray-100{color:#f3f4f6}
|
||||
.text-green-800{color:#065f46}
|
||||
.text-green-100{color:#dcfce7}
|
||||
.text-red-800{color:#991b1b}
|
||||
.text-red-200{color:#fecaca}
|
||||
.text-red-100{color:#fee2e2}
|
||||
.text-cyan-800{color:#155e75}
|
||||
.text-cyan-100{color:#cffafe}
|
||||
.text-base{font-size:1rem;line-height:1.5rem}
|
||||
.text-lg{font-size:1.125rem;line-height:1.75rem}
|
||||
.text-2xl{font-size:1.5rem;line-height:2rem}
|
||||
@@ -78,5 +101,12 @@ img{display:block;max-width:100%;height:auto}
|
||||
|
||||
/* Utilities */
|
||||
.hover\:bg-transparent:hover{background-color:transparent}
|
||||
.hover\:bg-gray-200:hover{background-color:#e5e7eb}
|
||||
.hover\:bg-gray-600:hover{background-color:#4b5563}
|
||||
.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}
|
||||
.focus\:ring-blue-200:focus{--tw-ring-color:rgba(191, 219, 254, var(--tw-ring-opacity))}
|
||||
.focus\:ring-blue-500:focus{--tw-ring-color:rgba(59, 130, 246, var(--tw-ring-opacity))}
|
||||
.disabled\:opacity-50:disabled{opacity:.5}
|
||||
.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}
|
||||
|
||||
/* Height for avatar images in header already inherit from container */
|
||||
|
||||
@@ -6,7 +6,24 @@
|
||||
<title>Nostr Relay</title>
|
||||
<link rel="stylesheet" href="tailwind.min.css" />
|
||||
</head>
|
||||
<body class="bg-white">
|
||||
<body>
|
||||
<script>
|
||||
// Apply system theme preference immediately to avoid flash of wrong theme
|
||||
function applyTheme(isDark) {
|
||||
document.body.classList.remove('bg-white', 'bg-gray-900');
|
||||
document.body.classList.add(isDark ? 'bg-gray-900' : 'bg-white');
|
||||
}
|
||||
|
||||
// Set initial theme
|
||||
applyTheme(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
|
||||
// Listen for theme changes
|
||||
if (window.matchMedia) {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
|
||||
applyTheme(e.matches);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.jsx"></script>
|
||||
</body>
|
||||
|
||||
32
app/web/public/tailwind.min.css
vendored
32
app/web/public/tailwind.min.css
vendored
@@ -39,26 +39,49 @@ img{display:block;max-width:100%;height:auto}
|
||||
.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}
|
||||
.border-0{border-width:0}.border-2{border-width:2px}
|
||||
.border-white{border-color:#fff}
|
||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}
|
||||
.border{border-width:1px}.border-gray-300{border-color:#d1d5db}.border-gray-600{border-color:#4b5563}
|
||||
.border-red-500{border-color:#ef4444}.border-red-700{border-color:#b91c1c}
|
||||
|
||||
/* Colors / Backgrounds */
|
||||
.bg-white{background-color:#fff}
|
||||
.bg-gray-100{background-color:#f3f4f6}
|
||||
.bg-gray-200{background-color:#e5e7eb}
|
||||
.bg-gray-300{background-color:#d1d5db}
|
||||
.bg-gray-600{background-color:#4b5563}
|
||||
.bg-gray-700{background-color:#374151}
|
||||
.bg-gray-800{background-color:#1f2937}
|
||||
.bg-gray-900{background-color:#111827}
|
||||
.bg-blue-500{background-color:#3b82f6}
|
||||
.bg-blue-600{background-color:#2563eb}.hover\:bg-blue-700:hover{background-color:#1d4ed8}
|
||||
.hover\:bg-blue-600:hover{background-color:#2563eb}
|
||||
.bg-red-600{background-color:#dc2626}.hover\:bg-red-700:hover{background-color:#b91c1c}
|
||||
.bg-cyan-100{background-color:#cffafe}
|
||||
.bg-green-100{background-color:#d1fae5}
|
||||
.bg-red-100{background-color:#fee2e2}
|
||||
.bg-red-50{background-color:#fef2f2}
|
||||
.bg-green-900{background-color:#064e3b}
|
||||
.bg-red-900{background-color:#7f1d1d}
|
||||
.bg-cyan-900{background-color:#164e63}
|
||||
.bg-cover{background-size:cover}.bg-center{background-position:center}
|
||||
.bg-transparent{background-color:transparent}
|
||||
|
||||
/* Text */
|
||||
.text-left{text-align:left}
|
||||
.text-white{color:#fff}
|
||||
.text-gray-300{color:#d1d5db}
|
||||
.text-gray-500{color:#6b7280}.hover\:text-gray-800:hover{color:#1f2937}
|
||||
.hover\:text-gray-100:hover{color:#f3f4f6}
|
||||
.text-gray-700{color:#374151}
|
||||
.text-gray-800{color:#1f2937}
|
||||
.text-gray-900{color:#111827}
|
||||
.text-gray-100{color:#f3f4f6}
|
||||
.text-green-800{color:#065f46}
|
||||
.text-green-100{color:#dcfce7}
|
||||
.text-red-800{color:#991b1b}
|
||||
.text-red-200{color:#fecaca}
|
||||
.text-red-100{color:#fee2e2}
|
||||
.text-cyan-800{color:#155e75}
|
||||
.text-cyan-100{color:#cffafe}
|
||||
.text-base{font-size:1rem;line-height:1.5rem}
|
||||
.text-lg{font-size:1.125rem;line-height:1.75rem}
|
||||
.text-2xl{font-size:1.5rem;line-height:2rem}
|
||||
@@ -78,5 +101,12 @@ img{display:block;max-width:100%;height:auto}
|
||||
|
||||
/* Utilities */
|
||||
.hover\:bg-transparent:hover{background-color:transparent}
|
||||
.hover\:bg-gray-200:hover{background-color:#e5e7eb}
|
||||
.hover\:bg-gray-600:hover{background-color:#4b5563}
|
||||
.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}
|
||||
.focus\:ring-blue-200:focus{--tw-ring-color:rgba(191, 219, 254, var(--tw-ring-opacity))}
|
||||
.focus\:ring-blue-500:focus{--tw-ring-color:rgba(59, 130, 246, var(--tw-ring-opacity))}
|
||||
.disabled\:opacity-50:disabled{opacity:.5}
|
||||
.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}
|
||||
|
||||
/* Height for avatar images in header already inherit from container */
|
||||
|
||||
1033
app/web/src/App.jsx
1033
app/web/src/App.jsx
File diff suppressed because it is too large
Load Diff
@@ -130,8 +130,8 @@ button:hover {
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 2px solid white;
|
||||
|
||||
@@ -70,11 +70,14 @@ func (d *D) QueryEvents(c context.Context, f *filter.F) (
|
||||
// Process each successfully fetched event and apply filters
|
||||
for serialValue, ev := range fetchedEvents {
|
||||
idHex := idHexToSerial[serialValue]
|
||||
|
||||
|
||||
// Convert serial value back to Uint40 for expiration handling
|
||||
ser := new(types.Uint40)
|
||||
if err = ser.Set(serialValue); err != nil {
|
||||
log.T.F("QueryEvents: error converting serial %d: %v", serialValue, err)
|
||||
log.T.F(
|
||||
"QueryEvents: error converting serial %d: %v", serialValue,
|
||||
err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -241,7 +244,7 @@ func (d *D) QueryEvents(c context.Context, f *filter.F) (
|
||||
// For replaceable events, we need to check if there are any
|
||||
// e-tags that reference events with the same kind and pubkey
|
||||
for _, eTag := range eTags {
|
||||
if eTag.Len() < 2 {
|
||||
if eTag.Len() != 64 {
|
||||
continue
|
||||
}
|
||||
// Get the event ID from the e-tag
|
||||
|
||||
@@ -1 +1 @@
|
||||
v0.6.0
|
||||
v0.6.3
|
||||
Reference in New Issue
Block a user