lens @ 91f7c40479aa9ef18c7927913be49a014a8a3115

feat: Add detail page
diff --git a/pkg/view/media.go b/pkg/view/media.go
index 8a10fe0792a75afa70e81bd0cc05b080012c4c80..88ecaf2e3247dbfa0b54afe1fb165282928e063f 100644
--- a/pkg/view/media.go
+++ b/pkg/view/media.go
@@ -3,6 +3,7 @@
 import (
 	"net/http"
 	"strconv"
+	"strings"
 
 	"git.sr.ht/~gabrielgio/img/pkg/database/repository"
 	"git.sr.ht/~gabrielgio/img/pkg/ext"
@@ -103,6 +104,41 @@
 	return nil
 }
 
+func (self *MediaView) Detail(w http.ResponseWriter, r *http.Request) error {
+	user := ext.GetUserFromCtx(r)
+
+	userPath, err := self.userRepository.GetPathFromUserID(r.Context(), user.ID)
+	if err != nil {
+		return err
+	}
+
+	pathHash := r.FormValue("path_hash")
+
+	media, err := self.mediaRepository.Get(r.Context(), pathHash)
+	if err != nil {
+		return err
+	}
+
+	if !strings.Contains(media.Path, userPath) {
+		ext.NotFound(w)
+		return nil
+	}
+
+	settings, err := self.settingsRepository.Load(r.Context())
+	if err != nil {
+		return err
+	}
+
+	page := &templates.DetailPage{
+		Settings: settings,
+		Media:    media,
+	}
+
+	templates.WritePageTemplate(w, page, user.IsAdmin)
+
+	return nil
+}
+
 func (self *MediaView) GetImage(w http.ResponseWriter, r *http.Request) error {
 	pathHash := r.FormValue("path_hash")
 
@@ -134,6 +170,9 @@
 func (self *MediaView) SetMyselfIn(r *ext.Router) {
 	r.GET("/media", self.Index)
 	r.POST("/media", self.Index)
+
+	r.GET("/detail", self.Detail)
+	r.POST("/detail", self.Detail)
 
 	r.GET("/media/image", self.GetImage)
 	r.GET("/media/thumbnail", self.GetThumbnail)
diff --git a/templates/detail.qtpl b/templates/detail.qtpl
new file mode 100644
index 0000000000000000000000000000000000000000..a981be9a83f2dcf3837a3286d3dbf11402390fc4
--- /dev/null
+++ b/templates/detail.qtpl
@@ -0,0 +1,34 @@
+{% import "git.sr.ht/~gabrielgio/img/pkg/database/repository" %}
+
+{% code
+type DetailPage struct {
+	Media   *repository.Media
+	Settings *repository.Settings
+}
+
+func (m *DetailPage) PreloadAttr() string {
+    if m.Settings.PreloadVideoMetadata {
+        return "metadata"
+    }
+    return "none"
+}
+%}
+
+{% func (p *DetailPage) Title() %}Media{% endfunc %}
+
+{% func (p *DetailPage) Content() %}
+<div class="card-image">
+    {% if p.Media.IsVideo() %}
+    <video class="image is-fit" controls muted="true" poster="/media/thumbnail?path_hash={%s p.Media.PathHash %}" preload="{%s p.PreloadAttr() %}">
+        <source src="/media/image?path_hash={%s p.Media.PathHash %}" type="{%s p.Media.MIMEType %}">
+    </video>
+    {% else %}
+     <figure class="image is-fit">
+        <img src="/media/image?path_hash={%s p.Media.PathHash %}">
+    </figure>
+    {% endif %}
+</div>
+{% endfunc %}
+
+{% func (p *DetailPage) Script() %}
+{% endfunc %}
diff --git a/templates/mosaic.qtpl b/templates/mosaic.qtpl
index 18dbcba489fef78faa1326522e834762f3efadba..21a8bae9560e8e3c9b07bfd4aa75a66ec2465360 100644
--- a/templates/mosaic.qtpl
+++ b/templates/mosaic.qtpl
@@ -7,14 +7,16 @@ {% for _, c := range list.Distribuite(medias, 6) %}
     <div class="column is-2">
     {% for _, media := range c %}
     <div class="card-image">
+       <a href="/detail?path_hash={%s media.PathHash %}">
        {% if media.IsVideo() %}
        <video class="image is-fit" controls muted="true" poster="/media/thumbnail?path_hash={%s media.PathHash %}" preload="{%s preloadAttr %}">
            <source src="/media/image?path_hash={%s media.PathHash %}" type="{%s media.MIMEType %}">
        </video>
        {% else %}
-        <figure class="image is-fit">
-            <img src="/media/thumbnail?path_hash={%s media.PathHash %}">
-        </figure>
+       <figure class="image is-fit">
+           <img src="/media/thumbnail?path_hash={%s media.PathHash %}">
+       </figure>
+       </a>
         {% endif %}
     </div>
     {% endfor %}