diff --git a/views/views_image-frame.templ b/views/views_image-frame.templ new file mode 100644 index 0000000..e2dc0de --- /dev/null +++ b/views/views_image-frame.templ @@ -0,0 +1,27 @@ +package views + +import "github.com/damongolding/immich-kiosk/immich" + +// frame is a template function that renders a basic frame for an image. +// It wraps the child content in a div with the class "frame--image". +templ frame() { +
+ { children... } +
+} + +// frameWithZoom is a template function that renders a frame with zoom effect for an image. +// It takes the refresh interval, image effect type, and the image asset as parameters. +// Depending on the image effect, it applies different CSS classes for zooming. +templ frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) { + switch imageEffect { + case "smart-zoom": +
+ { children... } +
+ default: +
+ { children... } +
+ } +} diff --git a/views/views_image-frame_templ.go b/views/views_image-frame_templ.go new file mode 100644 index 0000000..eb60477 --- /dev/null +++ b/views/views_image-frame_templ.go @@ -0,0 +1,144 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.778 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "github.com/damongolding/immich-kiosk/immich" + +// frame is a template function that renders a basic frame for an image. +// It wraps the child content in a div with the class "frame--image". +func frame() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +// frameWithZoom is a template function that renders a frame with zoom effect for an image. +// It takes the refresh interval, image effect type, and the image asset as parameters. +// Depending on the image effect, it applies different CSS classes for zooming. +func frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch imageEffect { + case "smart-zoom": + var templ_7745c5c3_Var3 = []any{"frame--image", "frame--image-zoom", animationDuration(refresh), zoomInOrOut(imageEffect), smartZoom(img)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + var templ_7745c5c3_Var5 = []any{"frame--image", "frame--image-zoom", animationDuration(refresh), zoomInOrOut(imageEffect)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return templ_7745c5c3_Err + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/views/views_image-metadata.templ b/views/views_image-metadata.templ new file mode 100644 index 0000000..25d2cf1 --- /dev/null +++ b/views/views_image-metadata.templ @@ -0,0 +1,122 @@ +package views + +import ( + "fmt" + "strings" + "time" + + "github.com/damongolding/immich-kiosk/config" + "github.com/damongolding/immich-kiosk/immich" + "github.com/damongolding/immich-kiosk/utils" +) + +// ImageLocation generates a formatted string of the image location based on EXIF information. +// It combines the city, state, and country information if available. +func ImageLocation(info immich.ExifInfo) string { + var location strings.Builder + + if info.City != "" { + location.WriteString(info.City) + } + + if info.State != "" { + location.WriteString(", ") + location.WriteString(info.State) + } + + if info.Country != "" { + location.WriteString(",
") + location.WriteString(info.Country) + } + + return location.String() +} + +// ImageExif generates a formatted string of EXIF information for an image. +// It includes f-number, exposure time, focal length, and ISO if available. +func ImageExif(info immich.ExifInfo) string { + var stats strings.Builder + + if info.FNumber != 0 { + stats.WriteString(fmt.Sprintf("ƒ/%.1f", info.FNumber)) + } + + if info.ExposureTime != "" { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("%ss", info.ExposureTime)) + } + + if info.FocalLength != 0 { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("%vmm", info.FocalLength)) + } + + if info.Iso != 0 { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("ISO %v", info.Iso)) + } + + return stats.String() +} + +// ImageDateTime generates a formatted date and time string for an image based on the view data settings. +// It can display date, time, or both, in various formats. +func ImageDateTime(viewData ViewData, imageIndex int) string { + var imageDate string + + var imageTimeFormat string + if viewData.ImageTimeFormat == "12" { + imageTimeFormat = time.Kitchen + } else { + imageTimeFormat = time.TimeOnly + } + + imageDateFormat := utils.DateToLayout(viewData.ImageDateFormat) + if imageDateFormat == "" { + imageDateFormat = config.DefaultDateLayout + } + + switch { + case (viewData.ShowImageDate && viewData.ShowImageTime): + imageDate = fmt.Sprintf("%s %s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat), viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) + case viewData.ShowImageDate: + imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) + case viewData.ShowImageTime: + imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat)) + } + + return imageDate +} + +// imageMetadata renders the metadata for an image, including date, time, EXIF information, location, and ID. +// The display of each piece of information is controlled by the ViewData settings. +templ imageMetadata(viewData ViewData, imageIndex int) { +
+ if viewData.ShowImageDate || viewData.ShowImageTime { +
+ { ImageDateTime(viewData, imageIndex) } +
+ } + if viewData.ShowImageExif { +
+ @templ.Raw(ImageExif(viewData.Images[imageIndex].ImmichImage.ExifInfo)) +
+ } + if viewData.ShowImageLocation { +
+ @templ.Raw(ImageLocation(viewData.Images[imageIndex].ImmichImage.ExifInfo)) +
+ } + if viewData.ShowImageID { +
+ { viewData.Images[imageIndex].ImmichImage.ID } +
+ } +
+} diff --git a/views/views_image-metadata_templ.go b/views/views_image-metadata_templ.go new file mode 100644 index 0000000..4cdd464 --- /dev/null +++ b/views/views_image-metadata_templ.go @@ -0,0 +1,224 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.778 +package views + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "fmt" + "strings" + "time" + + "github.com/damongolding/immich-kiosk/config" + "github.com/damongolding/immich-kiosk/immich" + "github.com/damongolding/immich-kiosk/utils" +) + +// ImageLocation generates a formatted string of the image location based on EXIF information. +// It combines the city, state, and country information if available. +func ImageLocation(info immich.ExifInfo) string { + var location strings.Builder + + if info.City != "" { + location.WriteString(info.City) + } + + if info.State != "" { + location.WriteString(", ") + location.WriteString(info.State) + } + + if info.Country != "" { + location.WriteString(",
") + location.WriteString(info.Country) + } + + return location.String() +} + +// ImageExif generates a formatted string of EXIF information for an image. +// It includes f-number, exposure time, focal length, and ISO if available. +func ImageExif(info immich.ExifInfo) string { + var stats strings.Builder + + if info.FNumber != 0 { + stats.WriteString(fmt.Sprintf("ƒ/%.1f", info.FNumber)) + } + + if info.ExposureTime != "" { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("%ss", info.ExposureTime)) + } + + if info.FocalLength != 0 { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("%vmm", info.FocalLength)) + } + + if info.Iso != 0 { + if stats.Len() > 0 { + stats.WriteString("|") + } + stats.WriteString(fmt.Sprintf("ISO %v", info.Iso)) + } + + return stats.String() +} + +// ImageDateTime generates a formatted date and time string for an image based on the view data settings. +// It can display date, time, or both, in various formats. +func ImageDateTime(viewData ViewData, imageIndex int) string { + var imageDate string + + var imageTimeFormat string + if viewData.ImageTimeFormat == "12" { + imageTimeFormat = time.Kitchen + } else { + imageTimeFormat = time.TimeOnly + } + + imageDateFormat := utils.DateToLayout(viewData.ImageDateFormat) + if imageDateFormat == "" { + imageDateFormat = config.DefaultDateLayout + } + + switch { + case (viewData.ShowImageDate && viewData.ShowImageTime): + imageDate = fmt.Sprintf("%s %s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat), viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) + case viewData.ShowImageDate: + imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) + case viewData.ShowImageTime: + imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat)) + } + + return imageDate +} + +// imageMetadata renders the metadata for an image, including date, time, EXIF information, location, and ID. +// The display of each piece of information is controlled by the ViewData settings. +func imageMetadata(viewData ViewData, imageIndex int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var2 = []any{"image--metadata", fmt.Sprintf("image--metadata--theme-%s", viewData.Theme)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if viewData.ShowImageDate || viewData.ShowImageTime { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ImageDateTime(viewData, imageIndex)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image-metadata.templ`, Line: 103, Col: 41} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if viewData.ShowImageExif { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.Raw(ImageExif(viewData.Images[imageIndex].ImmichImage.ExifInfo)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if viewData.ShowImageLocation { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.Raw(ImageLocation(viewData.Images[imageIndex].ImmichImage.ExifInfo)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if viewData.ShowImageID { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(viewData.Images[imageIndex].ImmichImage.ID) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image-metadata.templ`, Line: 118, Col: 48} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/views/views_image.templ b/views/views_image.templ index 3dc2667..718d4d6 100644 --- a/views/views_image.templ +++ b/views/views_image.templ @@ -3,14 +3,138 @@ package views import ( "fmt" "github.com/charmbracelet/log" - "github.com/damongolding/immich-kiosk/config" "github.com/damongolding/immich-kiosk/immich" "github.com/damongolding/immich-kiosk/utils" "strings" - "time" ) -templ ImageFitCover(ImageData, imageFit string) { +// Image is the main entry point for rendering images. +// It determines whether to use a single or split view layout based on the number of images, +// and renders the history form. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +templ Image(viewData ViewData) { + if len(viewData.Images) < 2 { + @layoutSingleView(viewData) + } else { + @layoutSplitView(viewData) + } + @renderHistory(viewData) +} + +// layoutSingleView renders a single image layout. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the image. +templ layoutSingleView(viewData ViewData) { + @layoutView(viewData, true) +} + +// layoutSplitView renders a split image layout for multiple images. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +templ layoutSplitView(viewData ViewData) { + @layoutView(viewData, false) +} + +// layoutView renders the layout for either a single image or multiple images. +// It applies the appropriate CSS classes and renders each image using renderSingleImage. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +// - isSingle: A boolean indicating whether this is a single image layout. +templ layoutView(viewData ViewData, isSingle bool) { +
+ if isSingle { + @renderSingleImage(viewData, viewData.Images[0], 0) + } else { + for imageIndex, imageData := range viewData.Images { +
+ @renderSingleImage(viewData, imageData, imageIndex) +
+ } + } +
+} + +// renderSingleImage renders a single image with its background and metadata. +// +// Parameters: +// - viewData: ViewData containing rendering settings. +// - imageData: ImageData for the image to be rendered. +// - imageIndex: The index of the image in the viewData.Images slice. +templ renderSingleImage(viewData ViewData, imageData ImageData, imageIndex int) { + @renderImageBackground(viewData, imageData) + @renderImage(viewData, imageData) + if !viewData.DisableUi { + @imageMetadata(viewData, imageIndex) + } +} + +// renderImageBackground renders a blurred background image if applicable. +// +// Parameters: +// - viewData: ViewData containing background blur settings. +// - imageData: ImageData containing the blur data for the image. +templ renderImageBackground(viewData ViewData, imageData ImageData) { + if viewData.BackgroundBlur && !strings.EqualFold(viewData.ImageFit, "cover") && len(imageData.ImageBlurData) > 0 { +
+ Blurred image background +
+ } +} + +// renderImage renders an image with the specified effect and fit. +// It applies zoom effects if specified, otherwise renders the image with the default frame. +// +// Parameters: +// - viewData: ViewData containing image effect and refresh settings. +// - imageData: ImageData containing the image data and ImmichImage. +// +// The function uses frameWithZoom for zoom effects and frame for default rendering. +// It delegates to RenderImageWithCoverFit or renderImageFit based on the image effect. +templ renderImage(viewData ViewData, imageData ImageData) { + switch strings.ToLower(viewData.ImageEffect) { + case "zoom", "smart-zoom": + @frameWithZoom(viewData.Refresh, viewData.ImageEffect, imageData.ImmichImage) { + @RenderImageWithCoverFit(imageData.ImageData, viewData.ImageFit) + } + default: + @frame() { + @renderImageFit(imageData.ImageData, viewData.ImageFit) + } + } +} + +// renderImageFit selects and renders the appropriate image fit template based on the imageFit parameter. +// +// Parameters: +// - imageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the desired image fit style ("cover", "none", or any other value for "contain"). +// +// The function uses a switch statement to determine which template to use: +// - "cover": Uses RenderImageWithCoverFit +// - "none": Uses RenderImageWithoutFit +// - Any other value: Uses RenderImageWithContainFit (default behavior) +templ renderImageFit(imageData string, imageFit string) { + switch strings.ToLower(imageFit) { + case "cover": + @RenderImageWithCoverFit(imageData, imageFit) + case "none": + @RenderImageWithoutFit(imageData, imageFit) + default: + @RenderImageWithContainFit(imageData, imageFit) + } +} + +// RenderImageWithCoverFit renders an image with "cover" fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +templ RenderImageWithCoverFit(ImageData, imageFit string) { } -templ ImageFitNone(ImageData, imageFit string) { +// RenderImageWithoutFit renders an image without any specific fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +templ RenderImageWithoutFit(ImageData, imageFit string) { Main image } -templ ImageFitContain(ImageData, imageFit string) { +// RenderImageWithContainFit renders an image with "contain" fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +templ RenderImageWithContainFit(ImageData, imageFit string) { } +// transformOrigin generates a CSS class for the transform-origin property. +// +// Parameters: +// - value: A string representing the desired transform origin value. +// +// Returns: +// - A CSS class for the transform-origin property. css transformOrigin(value string) { transform-origin: { value }; } +// smartZoom calculates the transform origin for an image based on detected faces. +// It returns a templ.CSSClass for the transform-origin CSS property. +// +// If no faces are detected, it returns a random corner as the transform origin. +// If faces are detected, it uses the center point of all faces as the transform origin. +// +// Parameters: +// - image: An immich.ImmichAsset containing information about detected faces. +// +// Returns: +// - templ.CSSClass: A CSS class for the transform-origin property. func smartZoom(image immich.ImmichAsset) templ.CSSClass { - if len(image.People) == 0 && len(image.UnassignedFaces) == 0 { log.Info("No FACES", "ID", image.ID) return transformOrigin(fmt.Sprintf("%s %s", utils.RandomItem([]string{"top", "bottom"}), utils.RandomItem([]string{"left", "right"}))) @@ -52,203 +203,13 @@ func smartZoom(image immich.ImmichAsset) templ.CSSClass { } return transformOrigin(fmt.Sprintf("%f%% %f%%", x, y)) - -} - -func ImageLocation(info immich.ExifInfo) string { - var location strings.Builder - - if info.City != "" { - location.WriteString(info.City) - } - - if info.State != "" { - location.WriteString(", ") - location.WriteString(info.State) - } - - if info.Country != "" { - location.WriteString(",
") - location.WriteString(info.Country) - } - - return location.String() -} - -func ImageExif(info immich.ExifInfo) string { - var stats strings.Builder - - if info.FNumber != 0 { - stats.WriteString(fmt.Sprintf("ƒ/%.1f", info.FNumber)) - } - - if info.ExposureTime != "" { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("%ss", info.ExposureTime)) - } - - if info.FocalLength != 0 { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("%vmm", info.FocalLength)) - } - - if info.Iso != 0 { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("ISO %v", info.Iso)) - } - - return stats.String() } -func ImageDateTime(viewData ViewData, imageIndex int) string { - var imageDate string - - var imageTimeFormat string - if viewData.ImageTimeFormat == "12" { - imageTimeFormat = time.Kitchen - } else { - imageTimeFormat = time.TimeOnly - } - - imageDateFormat := utils.DateToLayout(viewData.ImageDateFormat) - if imageDateFormat == "" { - imageDateFormat = config.DefaultDateLayout - } - - switch { - case (viewData.ShowImageDate && viewData.ShowImageTime): - imageDate = fmt.Sprintf("%s %s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat), viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) - case viewData.ShowImageDate: - imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) - case viewData.ShowImageTime: - imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat)) - } - - return imageDate -} - -templ imageMetadata(viewData ViewData, imageIndex int) { -
- if viewData.ShowImageDate || viewData.ShowImageTime { -
- { ImageDateTime(viewData, imageIndex) } -
- } - if viewData.ShowImageExif { -
- @templ.Raw(ImageExif(viewData.Images[imageIndex].ImmichImage.ExifInfo)) -
- } - if viewData.ShowImageLocation { -
- @templ.Raw(ImageLocation(viewData.Images[imageIndex].ImmichImage.ExifInfo)) -
- } - if viewData.ShowImageID { -
- { viewData.Images[imageIndex].ImmichImage.ID } -
- } -
-} - -templ frame() { -
- { children... } -
-} - -templ frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) { - switch imageEffect { - case "smart-zoom": -
- { children... } -
- default: -
- { children... } -
- } -} - -templ layoutSingleView(viewData ViewData) { -
- if viewData.BackgroundBlur && !strings.EqualFold(viewData.ImageFit, "cover") && len(viewData.Images[0].ImageBlurData) > 0 { -
- Blurred image background -
- } - switch strings.ToLower(viewData.ImageEffect) { - case "zoom", "smart-zoom": - @frameWithZoom(viewData.Refresh, viewData.ImageEffect, viewData.Images[0].ImmichImage) { - @ImageFitCover(viewData.Images[0].ImageData, viewData.ImageFit) - } - default: - @frame() { - switch strings.ToLower(viewData.ImageFit) { - case "cover": - @ImageFitCover(viewData.Images[0].ImageData, viewData.ImageFit) - case "none": - @ImageFitNone(viewData.Images[0].ImageData, viewData.ImageFit) - default: - @ImageFitContain(viewData.Images[0].ImageData, viewData.ImageFit) - } - } - } - if !viewData.DisableUi { - if !viewData.DisableUi { - @imageMetadata(viewData, 0) - } - } -
-} - -templ layoutSplitView(viewData ViewData) { -
- for imageIndex, imageData := range viewData.Images { -
- if viewData.BackgroundBlur && !strings.EqualFold(viewData.ImageFit, "cover") && len(imageData.ImageBlurData) > 0 { -
- Blurred image background -
- } - switch strings.ToLower(viewData.ImageEffect) { - case "zoom", "smart-zoom": - @frameWithZoom(viewData.Refresh, viewData.ImageEffect, viewData.Images[imageIndex].ImmichImage) { - @ImageFitCover(imageData.ImageData, viewData.ImageFit) - } - default: - @frame() { - switch strings.ToLower(viewData.ImageFit) { - case "cover": - @ImageFitCover(imageData.ImageData, viewData.ImageFit) - case "none": - @ImageFitNone(imageData.ImageData, viewData.ImageFit) - default: - @ImageFitContain(imageData.ImageData, viewData.ImageFit) - } - } - } - if !viewData.DisableUi { - @imageMetadata(viewData, imageIndex) - } -
- } -
-} - -templ Image(viewData ViewData) { - if len(viewData.Images) < 2 { - @layoutSingleView(viewData) - } else { - @layoutSplitView(viewData) - } +// renderHistory renders a form containing the viewing history of images. +// +// Parameters: +// - viewData: ViewData containing the history and current images. +templ renderHistory(viewData ViewData) {
for _, historyEntry := range viewData.History { diff --git a/views/views_image_templ.go b/views/views_image_templ.go index daebc82..60485c5 100644 --- a/views/views_image_templ.go +++ b/views/views_image_templ.go @@ -11,14 +11,18 @@ import templruntime "github.com/a-h/templ/runtime" import ( "fmt" "github.com/charmbracelet/log" - "github.com/damongolding/immich-kiosk/config" "github.com/damongolding/immich-kiosk/immich" "github.com/damongolding/immich-kiosk/utils" "strings" - "time" ) -func ImageFitCover(ImageData, imageFit string) templ.Component { +// Image is the main entry point for rendering images. +// It determines whether to use a single or split view layout based on the number of images, +// and renders the history form. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +func Image(viewData ViewData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -39,20 +43,18 @@ func ImageFitCover(ImageData, imageFit string) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"Main") + templ_7745c5c3_Err = renderHistory(viewData).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -60,7 +62,11 @@ func ImageFitCover(ImageData, imageFit string) templ.Component { }) } -func ImageFitNone(ImageData, imageFit string) templ.Component { +// layoutSingleView renders a single image layout. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the image. +func layoutSingleView(viewData ViewData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -76,25 +82,12 @@ func ImageFitNone(ImageData, imageFit string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var3 := templ.GetChildren(ctx) - if templ_7745c5c3_Var3 == nil { - templ_7745c5c3_Var3 = templ.NopComponent + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"Main") + templ_7745c5c3_Err = layoutView(viewData, true).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -102,7 +95,11 @@ func ImageFitNone(ImageData, imageFit string) templ.Component { }) } -func ImageFitContain(ImageData, imageFit string) templ.Component { +// layoutSplitView renders a split image layout for multiple images. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +func layoutSplitView(viewData ViewData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -118,25 +115,12 @@ func ImageFitContain(ImageData, imageFit string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"Main") + templ_7745c5c3_Err = layoutView(viewData, false).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -144,113 +128,13 @@ func ImageFitContain(ImageData, imageFit string) templ.Component { }) } -func transformOrigin(value string) templ.CSSClass { - templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() - templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`transform-origin`, value))) - templ_7745c5c3_CSSID := templ.CSSID(`transformOrigin`, templ_7745c5c3_CSSBuilder.String()) - return templ.ComponentCSSClass{ - ID: templ_7745c5c3_CSSID, - Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), - } -} - -func smartZoom(image immich.ImmichAsset) templ.CSSClass { - - if len(image.People) == 0 && len(image.UnassignedFaces) == 0 { - log.Info("No FACES", "ID", image.ID) - return transformOrigin(fmt.Sprintf("%s %s", utils.RandomItem([]string{"top", "bottom"}), utils.RandomItem([]string{"left", "right"}))) - } - - x, y := image.FacesCenterPoint() - - if x == 0 || y == 0 { - log.Info("No FACES", x, y, "ID", image.ID) - return transformOrigin(fmt.Sprintf("%s %s", utils.RandomItem([]string{"top", "bottom"}), utils.RandomItem([]string{"left", "right"}))) - } - - return transformOrigin(fmt.Sprintf("%f%% %f%%", x, y)) - -} - -func ImageLocation(info immich.ExifInfo) string { - var location strings.Builder - - if info.City != "" { - location.WriteString(info.City) - } - - if info.State != "" { - location.WriteString(", ") - location.WriteString(info.State) - } - - if info.Country != "" { - location.WriteString(",
") - location.WriteString(info.Country) - } - - return location.String() -} - -func ImageExif(info immich.ExifInfo) string { - var stats strings.Builder - - if info.FNumber != 0 { - stats.WriteString(fmt.Sprintf("ƒ/%.1f", info.FNumber)) - } - - if info.ExposureTime != "" { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("%ss", info.ExposureTime)) - } - - if info.FocalLength != 0 { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("%vmm", info.FocalLength)) - } - - if info.Iso != 0 { - if stats.Len() > 0 { - stats.WriteString("|") - } - stats.WriteString(fmt.Sprintf("ISO %v", info.Iso)) - } - - return stats.String() -} - -func ImageDateTime(viewData ViewData, imageIndex int) string { - var imageDate string - - var imageTimeFormat string - if viewData.ImageTimeFormat == "12" { - imageTimeFormat = time.Kitchen - } else { - imageTimeFormat = time.TimeOnly - } - - imageDateFormat := utils.DateToLayout(viewData.ImageDateFormat) - if imageDateFormat == "" { - imageDateFormat = config.DefaultDateLayout - } - - switch { - case (viewData.ShowImageDate && viewData.ShowImageTime): - imageDate = fmt.Sprintf("%s %s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat), viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) - case viewData.ShowImageDate: - imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageDateFormat)) - case viewData.ShowImageTime: - imageDate = fmt.Sprintf("%s", viewData.Images[imageIndex].ImmichImage.LocalDateTime.Format(imageTimeFormat)) - } - - return imageDate -} - -func imageMetadata(viewData ViewData, imageIndex int) templ.Component { +// layoutView renders the layout for either a single image or multiple images. +// It applies the appropriate CSS classes and renders each image using renderSingleImage. +// +// Parameters: +// - viewData: ViewData containing all necessary information for rendering the images. +// - isSingle: A boolean indicating whether this is a single image layout. +func layoutView(viewData ViewData, isSingle bool) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -266,13 +150,13 @@ func imageMetadata(viewData ViewData, imageIndex int) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var7 := templ.GetChildren(ctx) - if templ_7745c5c3_Var7 == nil { - templ_7745c5c3_Var7 = templ.NopComponent + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var8 = []any{"image--metadata", fmt.Sprintf("image--metadata--theme-%s", viewData.Theme)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + var templ_7745c5c3_Var5 = []any{"frame", templ.KV("frame-black-bg", !viewData.BackgroundBlur)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -280,12 +164,12 @@ func imageMetadata(viewData ViewData, imageIndex int) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var8).String()) + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var5).String()) if templ_7745c5c3_Err != nil { return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 1, Col: 0} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -293,70 +177,43 @@ func imageMetadata(viewData ViewData, imageIndex int) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - if viewData.ShowImageDate || viewData.ShowImageTime { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if isSingle { + templ_7745c5c3_Err = renderSingleImage(viewData, viewData.Images[0], 0).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(ImageDateTime(viewData, imageIndex)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 140, Col: 41} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if viewData.ShowImageExif { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(ImageExif(viewData.Images[imageIndex].ImmichImage.ExifInfo)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if viewData.ShowImageLocation { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(ImageLocation(viewData.Images[imageIndex].ImmichImage.ExifInfo)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if viewData.ShowImageID { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(viewData.Images[imageIndex].ImmichImage.ID) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 155, Col: 48} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + } else { + for imageIndex, imageData := range viewData.Images { + var templ_7745c5c3_Var7 = []any{fmt.Sprintf("frame--layout-%s", viewData.Layout)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = renderSingleImage(viewData, imageData, imageIndex).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") @@ -367,7 +224,13 @@ func imageMetadata(viewData ViewData, imageIndex int) templ.Component { }) } -func frame() templ.Component { +// renderSingleImage renders a single image with its background and metadata. +// +// Parameters: +// - viewData: ViewData containing rendering settings. +// - imageData: ImageData for the image to be rendered. +// - imageIndex: The index of the image in the viewData.Images slice. +func renderSingleImage(viewData ViewData, imageData ImageData, imageIndex int) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -383,28 +246,35 @@ func frame() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var12 := templ.GetChildren(ctx) - if templ_7745c5c3_Var12 == nil { - templ_7745c5c3_Var12 = templ.NopComponent + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + templ_7745c5c3_Err = renderImageBackground(viewData, imageData).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templ_7745c5c3_Var12.Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = renderImage(viewData, imageData).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + if !viewData.DisableUi { + templ_7745c5c3_Err = imageMetadata(viewData, imageIndex).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } return templ_7745c5c3_Err }) } -func frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) templ.Component { +// renderImageBackground renders a blurred background image if applicable. +// +// Parameters: +// - viewData: ViewData containing background blur settings. +// - imageData: ImageData containing the blur data for the image. +func renderImageBackground(viewData ViewData, imageData ImageData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -420,71 +290,26 @@ func frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) temp }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var13 := templ.GetChildren(ctx) - if templ_7745c5c3_Var13 == nil { - templ_7745c5c3_Var13 = templ.NopComponent + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - switch imageEffect { - case "smart-zoom": - var templ_7745c5c3_Var14 = []any{"frame--image", "frame--image-zoom", animationDuration(refresh), zoomInOrOut(imageEffect), smartZoom(img)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ_7745c5c3_Var13.Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - default: - var templ_7745c5c3_Var16 = []any{"frame--image", "frame--image-zoom", animationDuration(refresh), zoomInOrOut(imageEffect)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var16...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
0 { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(imageData.ImageBlurData) if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 84, Col: 37} } - templ_7745c5c3_Err = templ_7745c5c3_Var13.Render(ctx, templ_7745c5c3_Buffer) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" alt=\"Blurred image background\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -493,7 +318,16 @@ func frameWithZoom(refresh int, imageEffect string, img immich.ImmichAsset) temp }) } -func layoutSingleView(viewData ViewData) templ.Component { +// renderImage renders an image with the specified effect and fit. +// It applies zoom effects if specified, otherwise renders the image with the default frame. +// +// Parameters: +// - viewData: ViewData containing image effect and refresh settings. +// - imageData: ImageData containing the image data and ImmichImage. +// +// The function uses frameWithZoom for zoom effects and frame for default rendering. +// It delegates to RenderImageWithCoverFit or renderImageFit based on the image effect. +func renderImage(viewData ViewData, imageData ImageData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -509,55 +343,14 @@ func layoutSingleView(viewData ViewData) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var18 := templ.GetChildren(ctx) - if templ_7745c5c3_Var18 == nil { - templ_7745c5c3_Var18 = templ.NopComponent + templ_7745c5c3_Var12 := templ.GetChildren(ctx) + if templ_7745c5c3_Var12 == nil { + templ_7745c5c3_Var12 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var19 = []any{"frame", templ.KV("frame-black-bg", !viewData.BackgroundBlur)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var19...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if viewData.BackgroundBlur && !strings.EqualFold(viewData.ImageFit, "cover") && len(viewData.Images[0].ImageBlurData) > 0 { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
\"Blurred
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } switch strings.ToLower(viewData.ImageEffect) { case "zoom", "smart-zoom": - templ_7745c5c3_Var22 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_Var13 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { @@ -569,18 +362,18 @@ func layoutSingleView(viewData ViewData) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Err = ImageFitCover(viewData.Images[0].ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = RenderImageWithCoverFit(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } return templ_7745c5c3_Err }) - templ_7745c5c3_Err = frameWithZoom(viewData.Refresh, viewData.ImageEffect, viewData.Images[0].ImmichImage).Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer) + templ_7745c5c3_Err = frameWithZoom(viewData.Refresh, viewData.ImageEffect, imageData.ImmichImage).Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } default: - templ_7745c5c3_Var23 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_Var14 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) if !templ_7745c5c3_IsBuffer { @@ -592,39 +385,113 @@ func layoutSingleView(viewData ViewData) templ.Component { }() } ctx = templ.InitializeContext(ctx) - switch strings.ToLower(viewData.ImageFit) { - case "cover": - templ_7745c5c3_Err = ImageFitCover(viewData.Images[0].ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case "none": - templ_7745c5c3_Err = ImageFitNone(viewData.Images[0].ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - default: - templ_7745c5c3_Err = ImageFitContain(viewData.Images[0].ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } + templ_7745c5c3_Err = renderImageFit(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err } return templ_7745c5c3_Err }) - templ_7745c5c3_Err = frame().Render(templ.WithChildren(ctx, templ_7745c5c3_Var23), templ_7745c5c3_Buffer) + templ_7745c5c3_Err = frame().Render(templ.WithChildren(ctx, templ_7745c5c3_Var14), templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if !viewData.DisableUi { - if !viewData.DisableUi { - templ_7745c5c3_Err = imageMetadata(viewData, 0).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + return templ_7745c5c3_Err + }) +} + +// renderImageFit selects and renders the appropriate image fit template based on the imageFit parameter. +// +// Parameters: +// - imageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the desired image fit style ("cover", "none", or any other value for "contain"). +// +// The function uses a switch statement to determine which template to use: +// - "cover": Uses RenderImageWithCoverFit +// - "none": Uses RenderImageWithoutFit +// - Any other value: Uses RenderImageWithContainFit (default behavior) +func renderImageFit(imageData string, imageFit string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var15 := templ.GetChildren(ctx) + if templ_7745c5c3_Var15 == nil { + templ_7745c5c3_Var15 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch strings.ToLower(imageFit) { + case "cover": + templ_7745c5c3_Err = RenderImageWithCoverFit(imageData, imageFit).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + case "none": + templ_7745c5c3_Err = RenderImageWithoutFit(imageData, imageFit).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + templ_7745c5c3_Err = RenderImageWithContainFit(imageData, imageFit).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + return templ_7745c5c3_Err + }) +} + +// RenderImageWithCoverFit renders an image with "cover" fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +func RenderImageWithCoverFit(ImageData, imageFit string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"Main") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -632,7 +499,12 @@ func layoutSingleView(viewData ViewData) templ.Component { }) } -func layoutSplitView(viewData ViewData) templ.Component { +// RenderImageWithoutFit renders an image without any specific fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +func RenderImageWithoutFit(ImageData, imageFit string) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -648,148 +520,72 @@ func layoutSplitView(viewData ViewData) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var24 := templ.GetChildren(ctx) - if templ_7745c5c3_Var24 == nil { - templ_7745c5c3_Var24 = templ.NopComponent + templ_7745c5c3_Var18 := templ.GetChildren(ctx) + if templ_7745c5c3_Var18 == nil { + templ_7745c5c3_Var18 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - var templ_7745c5c3_Var25 = []any{"frame", templ.KV("frame-black-bg", !viewData.BackgroundBlur)} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var25...) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"Main") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") + return templ_7745c5c3_Err + }) +} + +// RenderImageWithContainFit renders an image with "contain" fit style. +// +// Parameters: +// - ImageData: A string containing the image data (typically a URL or base64-encoded image). +// - imageFit: A string specifying the image fit style (unused in this function). +func RenderImageWithContainFit(ImageData, imageFit string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if viewData.BackgroundBlur && !strings.EqualFold(viewData.ImageFit, "cover") && len(imageData.ImageBlurData) > 0 { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
\"Blurred
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - switch strings.ToLower(viewData.ImageEffect) { - case "zoom", "smart-zoom": - templ_7745c5c3_Var30 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Err = ImageFitCover(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) - templ_7745c5c3_Err = frameWithZoom(viewData.Refresh, viewData.ImageEffect, viewData.Images[imageIndex].ImmichImage).Render(templ.WithChildren(ctx, templ_7745c5c3_Var30), templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - default: - templ_7745c5c3_Var31 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - switch strings.ToLower(viewData.ImageFit) { - case "cover": - templ_7745c5c3_Err = ImageFitCover(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - case "none": - templ_7745c5c3_Err = ImageFitNone(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - default: - templ_7745c5c3_Err = ImageFitContain(imageData.ImageData, viewData.ImageFit).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - return templ_7745c5c3_Err - }) - templ_7745c5c3_Err = frame().Render(templ.WithChildren(ctx, templ_7745c5c3_Var31), templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if !viewData.DisableUi { - templ_7745c5c3_Err = imageMetadata(viewData, imageIndex).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } + var templ_7745c5c3_Var21 string + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(ImageData) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 165, Col: 17} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" alt=\"Main image\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -797,7 +593,55 @@ func layoutSplitView(viewData ViewData) templ.Component { }) } -func Image(viewData ViewData) templ.Component { +// transformOrigin generates a CSS class for the transform-origin property. +// +// Parameters: +// - value: A string representing the desired transform origin value. +// +// Returns: +// - A CSS class for the transform-origin property. +func transformOrigin(value string) templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`transform-origin`, value))) + templ_7745c5c3_CSSID := templ.CSSID(`transformOrigin`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +// smartZoom calculates the transform origin for an image based on detected faces. +// It returns a templ.CSSClass for the transform-origin CSS property. +// +// If no faces are detected, it returns a random corner as the transform origin. +// If faces are detected, it uses the center point of all faces as the transform origin. +// +// Parameters: +// - image: An immich.ImmichAsset containing information about detected faces. +// +// Returns: +// - templ.CSSClass: A CSS class for the transform-origin property. +func smartZoom(image immich.ImmichAsset) templ.CSSClass { + if len(image.People) == 0 && len(image.UnassignedFaces) == 0 { + log.Info("No FACES", "ID", image.ID) + return transformOrigin(fmt.Sprintf("%s %s", utils.RandomItem([]string{"top", "bottom"}), utils.RandomItem([]string{"left", "right"}))) + } + + x, y := image.FacesCenterPoint() + + if x == 0 || y == 0 { + log.Info("No FACES", x, y, "ID", image.ID) + return transformOrigin(fmt.Sprintf("%s %s", utils.RandomItem([]string{"top", "bottom"}), utils.RandomItem([]string{"left", "right"}))) + } + + return transformOrigin(fmt.Sprintf("%f%% %f%%", x, y)) +} + +// renderHistory renders a form containing the viewing history of images. +// +// Parameters: +// - viewData: ViewData containing the history and current images. +func renderHistory(viewData ViewData) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -813,22 +657,11 @@ func Image(viewData ViewData) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var32 := templ.GetChildren(ctx) - if templ_7745c5c3_Var32 == nil { - templ_7745c5c3_Var32 = templ.NopComponent + templ_7745c5c3_Var22 := templ.GetChildren(ctx) + if templ_7745c5c3_Var22 == nil { + templ_7745c5c3_Var22 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - if len(viewData.Images) < 2 { - templ_7745c5c3_Err = layoutSingleView(viewData).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = layoutSplitView(viewData).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err @@ -838,12 +671,12 @@ func Image(viewData ViewData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var33 string - templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(historyEntry) + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(historyEntry) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 254, Col: 88} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 215, Col: 88} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -857,12 +690,12 @@ func Image(viewData ViewData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var34 string - templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(newHistoryEntry.ImmichImage.ID) + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(newHistoryEntry.ImmichImage.ID) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 257, Col: 106} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 218, Col: 106} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }