mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
fix: virtual scroll jumping with images/GIFs
Server: - Extract image width/height on upload via image.DecodeConfig (header-only) - Add width/height columns to attachments table (migration 007) - Include dimensions in AttachmentInfo JSON (optional, backward-compatible) Client: - Reserve exact space for images using server-provided dimensions - Fallback min-height: 200px for external/old images, cleared on load - Remove premeasureAll() — was caching wrong heights for unloaded images - Smart per-type height estimates: 32px dividers, 42/72px text, +220px per image attachment, +320px for YouTube embeds - Batch ResizeObserver corrections to single RAF with anchor-based scroll preservation (topmost visible item stays in place) - Fenwick tree for O(log n) offset lookups (replaces O(n) linear scans) - CSS contain: layout style on .msg-image to isolate layout shift
This commit is contained in:
@@ -2,6 +2,10 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"log/slog"
|
||||
"mime"
|
||||
"net/http"
|
||||
@@ -21,6 +25,8 @@ type uploadResponse struct {
|
||||
Size int64 `json:"size"`
|
||||
Mime string `json:"mime"`
|
||||
URL string `json:"url"`
|
||||
Width *int `json:"width,omitempty"`
|
||||
Height *int `json:"height,omitempty"`
|
||||
}
|
||||
|
||||
// MountUploadRoutes registers upload and file-serving endpoints.
|
||||
@@ -78,8 +84,25 @@ func handleUpload(database *db.DB, store *storage.Storage) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// Extract image dimensions if the file is an image.
|
||||
var width, height *int
|
||||
if strings.HasPrefix(mime, "image/") {
|
||||
f, openErr := store.Open(fileID)
|
||||
if openErr == nil {
|
||||
cfg, _, decErr := image.DecodeConfig(f)
|
||||
f.Close() //nolint:errcheck
|
||||
if decErr == nil {
|
||||
w2, h2 := cfg.Width, cfg.Height
|
||||
width = &w2
|
||||
height = &h2
|
||||
} else {
|
||||
slog.Warn("failed to decode image dimensions", "id", fileID, "error", decErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert attachment record in DB (unlinked — message_id is NULL).
|
||||
if err := database.CreateAttachment(fileID, header.Filename, fileID, mime, header.Size); err != nil {
|
||||
if err := database.CreateAttachment(fileID, header.Filename, fileID, mime, header.Size, width, height); err != nil {
|
||||
// Clean up stored file on DB failure.
|
||||
_ = store.Delete(fileID)
|
||||
slog.Error("failed to create attachment record", "error", err)
|
||||
@@ -98,6 +121,8 @@ func handleUpload(database *db.DB, store *storage.Storage) http.HandlerFunc {
|
||||
Size: header.Size,
|
||||
Mime: mime,
|
||||
URL: "/api/v1/files/" + fileID,
|
||||
Width: width,
|
||||
Height: height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user