feat: add cards templete

This commit is contained in:
2026-06-24 10:47:54 +03:30
parent 60494946d6
commit b1c7bfdd06
124 changed files with 422 additions and 30 deletions
+47
View File
@@ -0,0 +1,47 @@
// Package static سرویس‌دهیِ تصاویرِ کارت (هر اسکین یک پوشه) را انجام می‌دهد.
// دو منبع: ۱) پوشه‌ی دیسکیِ ماندگار (diskDir) برای اسکین‌هایی که از پنل ادمین
// آپلود می‌شوند، ۲) فایل‌سیستمِ embed‌شده برای اسکین‌های پیش‌فرض (simple/epic).
// ابتدا دیسک بررسی می‌شود، سپس embed؛ پس آپلودها بدونِ کامپایلِ دوباره سرو می‌شوند.
// مسیر: GET /cards/<skin>/<code>.png و /cards/<skin>/back.jpg
package static
import (
"embed"
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
)
//go:embed cards
var cardsFS embed.FS
// CardsHandler یک http.Handler برای سرویس‌دهیِ فایل‌های کارت زیر /cards/ است.
// diskDir پوشه‌ی اسکین‌های آپلودی است (می‌تواند خالی/ناموجود باشد).
// CORS باز است تا نسخهٔ وب (Flutter web / canvaskit) هم بتواند تصاویر را بکشد.
func CardsHandler(diskDir string) http.Handler {
sub, err := fs.Sub(cardsFS, "cards")
if err != nil {
panic(err)
}
embedded := http.StripPrefix("/cards/", http.FileServer(http.FS(sub)))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Cache-Control", "public, max-age=604800") // یک هفته کش
// تلاشِ اول: پوشه‌ی دیسکی (اسکین‌های آپلودشده از پنل ادمین).
if diskDir != "" {
rel := strings.TrimPrefix(r.URL.Path, "/cards/")
rel = filepath.Clean("/" + rel) // جلوگیری از path traversal
full := filepath.Join(diskDir, rel)
if st, err := os.Stat(full); err == nil && !st.IsDir() {
http.ServeFile(w, r, full)
return
}
}
// تلاشِ دوم: اسکین‌های embed‌شده (simple/epic).
embedded.ServeHTTP(w, r)
})
}