PageSourceSearch

https://smartsignpro.ai/assets/controllers/category_card_preview_c…a53109fd908fece3cde3fcf3781ecc91bcd8c751.js

js smartsignpro.ai collected 2026-10-02 00:42:23 UTC 3,148 bytes, 94 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3// Live preview for storefront category cards: updates text color and background
4// image as staff adjust the theme settings.
5export default class extends Controller {
6  static targets = ["textColor", "textColorLabel", "primaryColor", "primaryColorLabel", "sourceImage", "card", "title", "subtitle"]
7  static values = {
8    defaultTextColor: { type: String, default: "#ffffff" },
9    sampleTitle: { type: String, default: "Burgers" },
10    sampleSubtitle: { type: String, default: "Tap to browse this category" }
11  }
12
13  connect() {
14    this.update()
15    this.observeSourceImage()
16  }
17
18  disconnect() {
19    this.sourceObserver?.disconnect()
20  }
21
22  updatePrimaryLabel() {
23    if (this.hasPrimaryColorTarget && this.hasPrimaryColorLabelTarget) {
24      this.primaryColorLabelTarget.textContent = this.primaryColorTarget.value
25    }
26  }
27
28  update() {
29    const textColor = this.hasTextColorTarget
30      ? (this.textColorTarget.value || this.defaultTextColorValue)
31      : this.defaultTextColorValue
32    const primary = this.hasPrimaryColorTarget
33      ? (this.primaryColorTarget.value || "#570df8")
34      : "#570df8"
35    const imageUrl = this.currentImageUrl()
36
37    if (this.hasTextColorLabelTarget) {
38      this.textColorLabelTarget.textContent = textColor
39    }
40
41    if (this.hasCardTarget) {
42      this.cardTarget.style.color = textColor
43      if (imageUrl) {
44        this.cardTarget.style.backgroundImage =
45          `linear-gradient(to top, rgba(0,0,0,.55), rgba(0,0,0,.15)), url('${imageUrl}')`
46        this.cardTarget.style.backgroundSize = "cover"
47        this.cardTarget.style.backgroundPosition = "center"
48        this.cardTarget.style.backgroundColor = ""
49      } else {
50        this.cardTarget.style.backgroundImage = ""
51        this.cardTarget.style.backgroundColor = primary
52      }
53    }
54
55    if (this.hasTitleTarget) {
56      this.titleTarget.style.color = textColor
57      this.titleTarget.style.textShadow = imageUrl ? "0 1px 2px rgb(0 0 0 / 35%)" : "none"
58    }
59
60    if (this.hasSubtitleTarget) {
61      this.subtitleTarget.style.color = textColor
62      this.subtitleTarget.style.opacity = "0.9"
63      this.subtitleTarget.style.textShadow = imageUrl ? "0 1px 2px rgb(0 0 0 / 35%)" : "none"
64    }
65  }
66
67  currentImageUrl() {
68    if (!this.hasSourceImageTarget) return null
69    const img = this.sourceImageTarget
70    if (img.classList.contains("hidden")) return null
71    const parent = img.closest("[data-image-upload-target='preview']")
72    if (parent?.classList.contains("hidden")) return null
73    const src = img.getAttribute("src")
74    return src && src.length > 0 ? src : null
75  }
76
77  observeSourceImage() {
78    if (!this.hasSourceImageTarget) return
79
80    this.sourceObserver = new MutationObserver(() => this.update())
81    this.sourceObserver.observe(this.sourceImageTarget, {
82      attributes: true,
83      attributeFilter: ["src", "class"]
84    })
85
86    const preview = this.sourceImageTarget.closest("[data-image-upload-target='preview']")
87    if (preview) {
88      this.sourceObserver.observe(preview, {
89        attributes: true,
90        attributeFilter: ["class"]
91      })
92    }
93  }
94};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.