lens @ 14e5580efd51c7b9e70d304715e512a2ea2a1b21

feat: Add option to download file
diff --git a/pkg/service/filesystem.go b/pkg/service/filesystem.go
index b4479ea3d5cea80dddb58e09f5265d3469f1964e..1364fd8deb7e0e01af4d4c509c07487ae7367e26 100644
--- a/pkg/service/filesystem.go
+++ b/pkg/service/filesystem.go
@@ -85,24 +85,32 @@ 	}
 	return result
 }
 
-func (self *FileSystemController) GetPage(ctx context.Context, userID uint, filepath string) (*Page, error) {
-	userPath, err := self.userRepository.GetPathFromUserID(ctx, userID)
+func (f *FileSystemController) GetFullpath(ctx context.Context, userID uint, filepath string) (string, error) {
+	userPath, err := f.userRepository.GetPathFromUserID(ctx, userID)
 	if err != nil {
-		return nil, err
+		return "", err
 	}
-	decodedPath, err := url.QueryUnescape(filepath)
+
+	return path.Join(userPath, filepath), nil
+}
+
+func (f *FileSystemController) IsFile(ctx context.Context, fullPath string) (bool, error) {
+	inf, err := f.fsRepository.Stat(fullPath)
 	if err != nil {
-		return nil, err
+		return false, err
 	}
 
-	fullPath := path.Join(userPath, decodedPath)
-	files, err := self.fsRepository.List(fullPath)
+	return !inf.IsDir(), nil
+}
+
+func (f *FileSystemController) GetPage(ctx context.Context, filename string, fullPath string) (*Page, error) {
+
+	files, err := f.fsRepository.List(fullPath)
 	if err != nil {
 		return nil, err
 	}
-
 	params := list.Map(files, func(info fs.FileInfo) *FileParam {
-		fullPath := path.Join(decodedPath, info.Name())
+		fullPath := path.Join(filename, info.Name())
 		scapedFullPath := url.QueryEscape(fullPath)
 		return &FileParam{
 			Info:           info,
@@ -112,6 +120,6 @@ 	})
 
 	return &Page{
 		Files:   params,
-		History: getHistory(decodedPath),
+		History: getHistory(filename),
 	}, nil
 }
diff --git a/pkg/view/filesystem.go b/pkg/view/filesystem.go
index 9071ec0e0cc95d53713c5e753d5a942539db8fec..f78f8a6b4196b3d58cf257351e0b59533251e11b 100644
--- a/pkg/view/filesystem.go
+++ b/pkg/view/filesystem.go
@@ -1,7 +1,9 @@
 package view
 
 import (
+	"mime"
 	"net/http"
+	"path/filepath"
 
 	"git.sr.ht/~gabrielgio/img/pkg/database/repository"
 	"git.sr.ht/~gabrielgio/img/pkg/ext"
@@ -37,7 +39,24 @@ 		pathValue = r.FormValue("path")
 		user      = ext.GetUserFromCtx(r)
 	)
 
-	page, err := self.fsService.GetPage(r.Context(), user.ID, pathValue)
+	fullpath, err := self.fsService.GetFullpath(r.Context(), user.ID, pathValue)
+	if err != nil {
+		return err
+	}
+
+	isFile, err := self.fsService.IsFile(r.Context(), fullpath)
+	if err != nil {
+		return err
+	}
+
+	if isFile {
+		mimetype := mime.TypeByExtension(filepath.Ext(fullpath))
+		w.Header().Set("Content-Type", mimetype)
+		http.ServeFile(w, r, fullpath)
+		return nil
+	}
+
+	page, err := self.fsService.GetPage(r.Context(), pathValue, fullpath)
 	if err != nil {
 		return err
 	}
diff --git a/templates/fs.qtpl b/templates/fs.qtpl
index 3dc2c5ab5912b7c9241d8a7a49a1ad5a9cf6051d..7ffc39ccf85192650c3a9a2fcb5d2405878ca3ef 100644
--- a/templates/fs.qtpl
+++ b/templates/fs.qtpl
@@ -25,11 +25,11 @@           <div class="column">
               <span class="text-size-2">
               {% if p.ShowMode %}{%s f.Info.Mode().String() %}&emsp;{% endif %}
               {% if p.ShowOwner %}{%d f.GetGid() %}:{%d f.GetUid() %}&emsp;{% endif %}
-              {% if f.Info.IsDir() %}
               </span>
+              {% if f.Info.IsDir() %}
               <a class="text-size-2" href="/?path={%s f.UrlEncodedPath %}">{%s f.Info.Name() %}/</a>
               {% else %}
-              {%s f.Info.Name() %}
+              <a class="text-size-2" href="/?path={%s f.UrlEncodedPath %}">{%s f.Info.Name() %}</a>
               {% endif %}
           </div>
           <div class="column text-size-2 has-text-right">{%dl f.Info.Size() %} B</div>