{"version":3,"file":"main.BPKApP.js","sources":["theme-46/virtual:theme","theme-46/discourse/lib/image-color-utils.js","theme-46/discourse/components/carousel.gjs","theme-46/discourse/api-initializers/carousel-api.js","theme-46/discourse/api-initializers/theme-initializer.gjs","theme-46/discourse/connectors/above-main-container/carousel.gjs","theme-46/discourse/helpers/range.js","theme-46/discourse/services/featured-topics.js","theme-46/virtual:entrypoint:main"],"sourcesContent":["import { getObjectForTheme } from \"discourse/lib/theme-settings-store\";\n\nexport const settings = getObjectForTheme(46);\n\nexport function themePrefix(key) {\n  return `theme_translations.46.${key}`;\n}\n","/**\n * Image Color Analysis Utilities\n *\n * This module provides utilities for extracting dominant colors from images\n * and generating appropriate text and accent colors for theming.\n */\n\n/**\n * Analyzes an image and extracts the most saturated color from different regions\n * @param {string} imageUrl - URL of the image to analyze\n * @param {Object} options - Configuration options\n * @param {number} options.regions - Number of regions to divide the image into (default: 8)\n * @param {number} options.minBrightness - Minimum brightness threshold (default: 50)\n * @returns {Promise<Object>} Color analysis result\n */\nexport async function extractDominantColor(imageUrl, options = {}) {\n  const config = {\n    regions: options.regions || 8,\n    minBrightness: options.minBrightness || 50,\n    ...options,\n  };\n\n  return new Promise((resolve, reject) => {\n    const canvas = document.createElement(\"canvas\");\n    const context = canvas.getContext(\"2d\", { willReadFrequently: true });\n    const img = new Image();\n\n    img.crossOrigin = \"anonymous\";\n    img.src = imageUrl;\n\n    img.onerror = () => {\n      reject(new Error(`Failed to load image: ${imageUrl}`));\n    };\n\n    img.onload = () => {\n      try {\n        canvas.width = img.naturalWidth || img.width;\n        canvas.height = img.naturalHeight || img.height;\n        context.drawImage(img, 0, 0);\n\n        const imgData = context.getImageData(0, 0, canvas.width, canvas.height).data;\n        const dominantColor = analyzeDominantColor(imgData, canvas.width, canvas.height, config);\n\n        resolve(dominantColor);\n      } catch (error) {\n        reject(error);\n      }\n    };\n  });\n}\n\n/**\n * Analyzes image data to find the most saturated color across regions\n * @param {Uint8ClampedArray} imgData - Image pixel data\n * @param {number} width - Image width\n * @param {number} height - Image height\n * @param {Object} config - Analysis configuration\n * @returns {Object} Analysis result with color and brightness info\n */\nfunction analyzeDominantColor(imgData, width, height, config) {\n  const { regions, minBrightness } = config;\n  const regionWidth = Math.floor(width / regions);\n  const regionHeight = Math.floor(height / regions);\n\n  let highestSaturation = 0;\n  let bestRegionColor = { r: 0, g: 0, b: 0 };\n\n  // Analyze each region to find the most saturated color\n  for (let regionX = 0; regionX < regions; regionX++) {\n    for (let regionY = 0; regionY < regions; regionY++) {\n      const regionResult = analyzeRegion(\n        imgData,\n        width,\n        regionX * regionWidth,\n        regionY * regionHeight,\n        regionWidth,\n        regionHeight,\n        minBrightness\n      );\n\n      if (regionResult.avgSaturation > highestSaturation) {\n        highestSaturation = regionResult.avgSaturation;\n        bestRegionColor = regionResult.avgColor;\n      }\n    }\n  }\n\n  const brightness = calculateBrightness(bestRegionColor);\n\n  return {\n    color: bestRegionColor,\n    saturation: highestSaturation,\n    brightness,\n  };\n}\n\n/**\n * Analyzes a specific region of the image\n * @param {Uint8ClampedArray} imgData - Image pixel data\n * @param {number} imgWidth - Image width\n * @param {number} startX - Region start X coordinate\n * @param {number} startY - Region start Y coordinate\n * @param {number} regionWidth - Region width\n * @param {number} regionHeight - Region height\n * @param {number} minBrightness - Minimum brightness threshold\n * @returns {Object} Region analysis result\n */\nfunction analyzeRegion(imgData, imgWidth, startX, startY, regionWidth, regionHeight, minBrightness) {\n  let regionSaturation = 0;\n  let regionPixelCount = 0;\n  let regionColorSum = { r: 0, g: 0, b: 0 };\n\n  for (let y = startY; y < startY + regionHeight; y++) {\n    for (let x = startX; x < startX + regionWidth; x++) {\n      const index = (y * imgWidth + x) * 4;\n      const r = imgData[index];\n      const g = imgData[index + 1];\n      const b = imgData[index + 2];\n      const brightness = (r + g + b) / 3;\n\n      // Skip very dark pixels\n      if (brightness < minBrightness) {continue;}\n\n      const saturation = calculateSaturation(r, g, b);\n\n      regionSaturation += saturation;\n      regionPixelCount++;\n      regionColorSum.r += r;\n      regionColorSum.g += g;\n      regionColorSum.b += b;\n    }\n  }\n\n  const avgSaturation = regionPixelCount > 0 ? regionSaturation / regionPixelCount : 0;\n  const avgColor = regionPixelCount > 0 ? {\n    r: Math.floor(regionColorSum.r / regionPixelCount),\n    g: Math.floor(regionColorSum.g / regionPixelCount),\n    b: Math.floor(regionColorSum.b / regionPixelCount),\n  } : { r: 0, g: 0, b: 0 };\n\n  return { avgSaturation, avgColor };\n}\n\n/**\n * Calculates the saturation of an RGB color\n * @param {number} r - Red component (0-255)\n * @param {number} g - Green component (0-255)\n * @param {number} b - Blue component (0-255)\n * @returns {number} Saturation value (0-1)\n */\nfunction calculateSaturation(r, g, b) {\n  const max = Math.max(r, g, b);\n  const min = Math.min(r, g, b);\n  const delta = max - min;\n  return max === 0 ? 0 : delta / max;\n}\n\n/**\n * Calculates the brightness of an RGB color using luminance formula\n * @param {Object} color - RGB color object\n * @param {number} color.r - Red component (0-255)\n * @param {number} color.g - Green component (0-255)\n * @param {number} color.b - Blue component (0-255)\n * @returns {number} Brightness value (0-1)\n */\nfunction calculateBrightness({ r, g, b }) {\n  return (r * 0.299 + g * 0.587 + b * 0.114) / 255;\n}\n\n/**\n * Generates theme colors based on a dominant color\n * @param {Object} dominantColor - Dominant color analysis result\n * @returns {Object} Theme color palette\n */\nexport function generateThemeColors(dominantColor) {\n  const { color, brightness } = dominantColor;\n  const isLight = brightness >= 0.5;\n\n  return {\n    accent: `${color.r},${color.g},${color.b}`,\n    text: isLight ? \"0,0,0\" : \"255,255,255\",\n    invert: isLight ? \"255,255,255\" : \"0,0,0\",\n    background: `${color.r},${color.g},${color.b}`,\n  };\n}\n\n/**\n * Applies theme colors to CSS custom properties for a specific element\n * @param {HTMLElement} element - Target element\n * @param {string} prefix - CSS property prefix (e.g., 'd-0', 'd-1')\n * @param {Object} themeColors - Theme color palette\n */\nexport function applyThemeColors(element, prefix, themeColors) {\n  if (!element) {return;}\n\n  element.style.setProperty(`--${prefix}-text-color-rgb`, themeColors.text);\n  element.style.setProperty(`--${prefix}-invert-color-rgb`, themeColors.invert);\n  element.style.setProperty(`--${prefix}-bg-color-rgb`, themeColors.background);\n  element.style.setProperty(`--${prefix}-accent-color-rgb`, themeColors.accent);\n}\n\n/**\n * High-level utility to extract colors from an image and apply theme\n * @param {string} imageUrl - Image URL\n * @param {HTMLElement} targetElement - Element to apply CSS properties to\n * @param {string} prefix - CSS property prefix\n * @param {Object} options - Extraction options\n */\nexport async function extractAndApplyImageTheme(imageUrl, targetElement, prefix, options = {}) {\n  try {\n    const dominantColor = await extractDominantColor(imageUrl, options);\n    const themeColors = generateThemeColors(dominantColor);\n    applyThemeColors(targetElement, prefix, themeColors);\n    return themeColors;\n  } catch (error) {\n    // eslint-disable-next-line no-console\n    console.warn(`Failed to extract theme from image ${imageUrl}:`, error);\n    return null;\n  }\n}","import Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { fn, get } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { action } from \"@ember/object\";\nimport { cancel } from \"@ember/runloop\";\nimport didInsert from \"@ember/render-modifiers/modifiers/did-insert\";\nimport didUpdate from \"@ember/render-modifiers/modifiers/did-update\";\nimport { htmlSafe } from \"@ember/template\";\nimport { and, gt, or } from \"truth-helpers\";\nimport ConditionalLoadingSpinner from \"discourse/components/conditional-loading-spinner\";\nimport DButton from \"discourse/components/d-button\";\nimport avatar from \"discourse/helpers/avatar\";\nimport categoryLink from \"discourse/helpers/category-link\";\nimport discourseTags from \"discourse/helpers/discourse-tags\";\nimport formatDate from \"discourse/helpers/format-date\";\nimport number from \"discourse/helpers/number\";\nimport replaceEmoji from \"discourse/helpers/replace-emoji\";\nimport icon from \"discourse-common/helpers/d-icon\";\nimport { extractAndApplyImageTheme } from \"../lib/image-color-utils\";\nimport discourseLater from \"discourse/lib/later\";\nimport { modifier as modifierFn } from \"ember-modifier\";\nimport { service } from \"@ember/service\";\n\nexport default class Carousel extends Component {\n  @service featuredTopics;\n  @tracked containerWidth = 0;\n  @tracked currentIndex = 0;\n  @tracked visibleCount = settings.topics_per_slide || 3;\n  autoplayInterval = null;\n  carouselElement = null;\n\n  // Screen size breakpoints for responsive behavior\n  static BREAKPOINT_MEDIUM = 1060; // Width where we start degrading from 3+ topics\n  static BREAKPOINT_SMALL = 800;   // Width where we further degrade topics\n\n  // Inline modifier for debounced resize observation\n  observeResize = modifierFn((element) => {\n    let debounceTimer = null;\n\n    const resizeObserver = new ResizeObserver((entries) => {\n      if (!entries?.[0]) return;\n\n      // Cancel previous debounced call\n      cancel(debounceTimer);\n\n      // Debounce for ~500ms after last resize frame, covers most animations such as sidebar\n      debounceTimer = discourseLater(() => {\n        const width = entries[0].contentRect.width;\n        this.containerWidth = width;\n        this.updateVisibleCount();\n      }, 500);\n    });\n\n    resizeObserver.observe(element);\n\n    return () => {\n      cancel(debounceTimer);\n      resizeObserver.disconnect();\n    };\n  });\n\n\n  get autoplayEnabled() {\n    return settings.autoplay > 0;\n  }\n\n  get shouldAutoplay() {\n    return this.autoplayEnabled && this.hasMoreTopics && !this.isLoading && this.topics.length > 0;\n  }\n\n  get topics() {\n    // If topics are passed directly, use them\n    if (this.args.topics) {\n      return this.args.topics;\n    }\n\n    // If tagName is provided, get topics for that specific tag\n    if (this.args.tagName) {\n      return this.featuredTopics.getTopicsForTag(this.args.category, this.args.tagName);\n    }\n\n    // Default fallback\n    return [];\n  }\n\n  get isLoading() {\n    // If isLoading is passed directly, use it\n    if (this.args.isLoading !== undefined) {\n      return this.args.isLoading;\n    }\n\n    // If tagName is provided, use loading state from service\n    if (this.args.tagName) {\n      return this.featuredTopics.isLoading ?? false;\n    }\n\n    // Default fallback\n    return false;\n  }\n\n  currentTopic = (offset) => {\n    if (this.topics.length === 0) return null;\n    return this.topics[(this.currentIndex + offset) % this.topics.length];\n  };\n\n  @action\n  updateVisibleCount() {\n    let degrade = 0;\n\n    if ((settings.topics_per_slide || 3) >= 3 && this.containerWidth < Carousel.BREAKPOINT_MEDIUM) {\n      degrade = 1;\n    }\n    if (this.containerWidth < Carousel.BREAKPOINT_SMALL) {\n      degrade = 2;\n    }\n\n    this.visibleCount = Math.max(1, (settings.topics_per_slide || 3) - degrade);\n  }\n\n  @action\n  storeCarouselElement(element) {\n    this.carouselElement = element;\n  }\n\n  @action\n  loadTopicsByTag() {\n    if (this.args.tagName && !this.args.topics) {\n      this.featuredTopics.getFeaturedTopics(this.args.category, this.args.tagName);\n    }\n  }\n\n\n  get visibleOffsets() {\n    return Array.from({ length: this.visibleCount }, (_, i) => i);\n  }\n\n  @action\n  setupAutoplay() {\n    // This will be called when component is inserted or topics change\n    if (this.shouldAutoplay) {\n      this.startAutoplay();\n    } else {\n      this.stopAutoplay();\n    }\n  }\n\n  get isCarousel() {\n    return this.visibleCount > 1;\n  }\n\n\n  @action\n  restartAutoplay() {\n    this.stopAutoplay();\n    this.startAutoplay();\n  }\n\n  @action\n  startAutoplay() {\n    if (!this.autoplayInterval) {\n      this.autoplayInterval = setInterval(() => {\n        this.nextIndex();\n      }, settings.autoplay * 1000);\n    }\n  }\n\n  @action\n  stopAutoplay() {\n    if (this.autoplayInterval) {\n      clearInterval(this.autoplayInterval);\n      this.autoplayInterval = null;\n    }\n  }\n\n  @action\n  handleMouseEnter() {\n    if (this.autoplayEnabled) {\n      this.stopAutoplay();\n    }\n  }\n\n  @action\n  handleMouseLeave() {\n    if (this.autoplayEnabled) {\n      this.startAutoplay();\n    }\n  }\n\n  updateCarouselClass(direction) {\n    if (!this.carouselElement) return;\n    this.carouselElement.classList.toggle(\"--next\", direction === \"next\");\n    this.carouselElement.classList.toggle(\"--prev\", direction === \"prev\");\n  }\n\n  @action\n  nextIndex() {\n    if (this.autoplayEnabled) this.restartAutoplay();\n    this.animateCarouselChange(() => {\n      this.currentIndex = (this.currentIndex + (this.visibleCount || 1)) % this.topics.length;\n      this.updateCarouselClass(\"next\");\n    });\n  }\n\n  @action\n  prevIndex() {\n    if (this.autoplayEnabled) this.restartAutoplay();\n    this.animateCarouselChange(() => {\n      this.currentIndex =\n        (this.currentIndex - (this.visibleCount || 1) + this.topics.length) %\n        this.topics.length;\n      this.updateCarouselClass(\"prev\");\n    });\n  }\n\n  @action\n  changeIndex(index) {\n    this.animateCarouselChange(() => {\n      this.currentIndex = index;\n    });\n  }\n\n  @action\n  animateCarouselChange(callback) {\n    if (!this.carouselElement) return;\n\n    const transitionDuration = 200;\n    const computedHeight = window.getComputedStyle(this.carouselElement).height;\n    this.carouselElement.style.height = computedHeight;\n\n    this.carouselElement.classList.add(\"--animate\");\n\n    discourseLater(() => {\n      callback();\n      this.carouselElement.classList.remove(\"--animate\");\n      this.carouselElement.style.height = \"\";\n    }, transitionDuration);\n  }\n\n  get hasMoreTopics() {\n    return this.topics.length > this.visibleCount;\n  }\n\n  get safeCarouselHeight() {\n    let styles = '';\n\n    // Only set CSS variable if image_height is valid (not 'unset' or empty)\n    if (settings.image_height && settings.image_height !== 'unset') {\n      styles += `--d-image-height: ${settings.image_height};`;\n    }\n\n    // Only set CSS variable if image_aspect_ratio is valid (not 'unset' or empty)\n    if (settings.image_aspect_ratio && settings.image_aspect_ratio !== 'unset') {\n      styles += ` --d-image-aspect-ratio: ${settings.image_aspect_ratio};`;\n    }\n\n    // If display_images setting is false, signal CSS to use auto height (text-only layout)\n    if (!settings.display_images) {\n      styles += ` --text-only-mode: true;`;\n    }\n\n    return htmlSafe(styles);\n  }\n\n  repliesCount(posts) {\n    return posts > 1 ? posts - 1 : null;\n  }\n\n  /**\n   * Get the header text - prioritizes passed argument over theme setting\n   */\n  get headerText() {\n    return this.args.header || settings.header || \"\";\n  }\n\n  /**\n   * Get the subheader text - prioritizes passed argument over theme setting\n   */\n  get subheaderText() {\n    return this.args.subheader || settings.subheader || \"\";\n  }\n\n  /**\n   * Handles image load event and applies theme colors\n   * @param {number} offset - Topic offset for current slide\n   * @param {Event} event - Image load event\n   */\n  @action\n  async handleImageLoad(offset, event) {\n    const img = event.target;\n    if (!img.src || !this.carouselElement) return;\n\n    // Apply image-based theme colors\n    await extractAndApplyImageTheme(\n      img.src,\n      this.carouselElement,\n      `d-${offset}`,\n      {\n        regions: 8,\n        minBrightness: 50,\n      }\n    );\n  }\n\n  <template>\n    <div\n      {{didInsert this.loadTopicsByTag}}\n      {{didUpdate this.loadTopicsByTag @tagName @category}}\n    >\n      {{#if this.topics}}\n        <div class=\"carousel-container\">\n          {{#if this.headerText}}\n            <h2 class=\"carousel-container__header\">{{this.headerText}}</h2>\n          {{/if}}\n          {{#if this.subheaderText}}\n            <p class=\"carousel-container__subheader\">{{this.subheaderText}}</p>\n          {{/if}}\n          <div\n            class=\"carousel-topics --{{settings.style}}\n              --{{settings.animation}}-animation\n              {{unless settings.display_images '--text-only'}}\n              {{unless settings.accent_colors '--no-accent'}}\"\n            style={{this.safeCarouselHeight}}\n            {{didInsert this.storeCarouselElement}}\n            {{didInsert this.setupAutoplay}}\n            {{didUpdate this.setupAutoplay this.topics}}\n            {{on \"mouseenter\" this.handleMouseEnter}}\n            {{on \"mouseleave\" this.handleMouseLeave}}\n            {{this.observeResize}}\n          >\n        <div class=\"carousel-topics__wrapper\">\n          {{#if this.hasMoreTopics}}\n            <DButton\n              @action={{this.prevIndex}}\n              @icon={{settings.arrow_left_icon}}\n              class=\"carousel-topics__btn --left btn-default\"\n            />\n          {{/if}}\n\n          <ConditionalLoadingSpinner @condition={{this.isLoading}}>\n            {{#each this.visibleOffsets as |offset|}}\n              {{#let (this.currentTopic offset) as |topic|}}\n                {{#if topic}}\n                  {{#let\n                    (if\n                      (and settings.display_images topic.image_url)\n                      topic.image_url\n                      settings.placeholder_image\n                    )\n                    as |imageSource|\n                  }}\n                    <a class=\"carousel-topics__link-wrapper{{if imageSource ' has-image'}}\" href=\"/t/{{topic.slug}}\">\n                  {{#if\n                    (or\n                      settings.display_titles\n                      settings.display_excerpts\n                      settings.display_categories\n                      settings.display_tags\n                      settings.display_op\n                      settings.display_like_counts\n                      settings.display_reply_counts\n                      settings.display_view_counts\n                      settings.display_last_posted_at\n                    )\n                  }}\n                    <div class=\"carousel-topics__inner\">\n                      {{#if settings.display_titles}}\n                        <h3 class=\"carousel-topics__title\">\n                          {{replaceEmoji (htmlSafe topic.title)}}\n                        </h3>\n                      {{/if}}\n\n                      {{#if settings.display_excerpts}}\n                        <p class=\"carousel-topics__excerpt\">\n                          {{replaceEmoji (htmlSafe topic.excerpt)}}\n                        </p>\n                      {{/if}}\n\n                      {{#if\n                        (or settings.display_categories settings.display_tags)\n                      }}\n                        <div class=\"carousel-topics__badges\">\n                          {{#if settings.display_categories}}\n                            {{categoryLink topic.category~}}\n                          {{/if}}\n                          {{#if settings.display_tags}}\n                            {{~discourseTags topic mode=\"list\"}}\n                          {{/if}}\n                        </div>\n                      {{/if}}\n\n                      <div class=\"carousel-topics__meta-data\">\n                        {{#if settings.display_op}}\n                          {{#let (get topic.posters \"0.user\") as |poster|}}\n                            <a\n                              {{! template-lint-disable no-nested-interactive }}\n                              class=\"carousel-topics__poster\"\n                              href={{topic.lastPostUrl}}\n                              data-user-card={{poster.username}}\n                            >\n                              {{avatar poster imageSize=\"small\"}}\n                              <span class=\"carousel-topics__username\">{{poster.username}}</span>\n                            </a>\n                          {{/let}}\n                        {{/if}}\n\n                        <div class=\"carousel-topics__stats\">\n                          {{#if\n                            (and settings.display_like_counts topic.like_count)\n                          }}\n                            <div class=\"carousel-topics__likes\">\n                              {{icon settings.likes_icon}}\n                              {{number topic.like_count}}\n                            </div>\n                          {{/if}}\n                          {{#if\n                            (and\n                              settings.display_reply_counts\n                              (gt topic.posts_count 1)\n                            )\n                          }}\n                            <div class=\"carousel-topics__replies\">\n                              {{icon settings.replies_icon}}\n                              {{number (this.repliesCount topic.posts_count)}}\n                            </div>\n                          {{/if}}\n\n                          {{#if (and settings.display_view_counts topic.views)}}\n                            <div class=\"carousel-topics__views\">\n                              {{icon settings.views_icon}}\n                              {{number topic.views numberKey=\"views_long\"}}\n                            </div>\n                          {{/if}}\n\n                          {{#if\n                            (and\n                              settings.display_last_posted_at topic.last_posted_at\n                            )\n                          }}\n                            <div class=\"carousel-topics__activity\">\n                              {{icon settings.activity_icon}}\n                              {{formatDate topic.last_posted_at format=\"tiny\"}}\n                            </div>\n                          {{/if}}\n                        </div>\n                      </div>\n                    </div>\n                  {{/if}}\n                    {{! Only render the <img> tag if *imageSource* is truthy }}\n                    {{#if imageSource}}\n                      {{#if settings.accent_colors}}\n                        <img\n                          class=\"carousel-topics__image\"\n                          src={{imageSource}}\n                          alt={{if\n                            (and settings.display_images topic.image_url)\n                            \"Topic Image\"\n                            \"Placeholder Image\"\n                          }}\n                          {{on \"load\" (fn this.handleImageLoad offset)}}\n                        />\n                      {{else}}\n                        <img\n                          class=\"carousel-topics__image\"\n                          src={{imageSource}}\n                          alt={{if\n                            (and settings.display_images topic.image_url)\n                            \"Topic Image\"\n                            \"Placeholder Image\"\n                          }}\n                        />\n                      {{/if}}\n                    {{/if}}\n                    </a>\n                  {{/let}}\n                {{/if}}\n              {{/let}}\n            {{/each}}\n          </ConditionalLoadingSpinner>\n\n          {{#if this.hasMoreTopics}}\n            <DButton\n              @action={{this.nextIndex}}\n              @icon={{settings.arrow_right_icon}}\n              class=\"carousel-topics__btn --right btn-default\"\n            />\n          {{/if}}\n        </div>\n        {{! pagination dots etc }}\n        </div>\n        </div>\n      {{/if}}\n    </div>\n  </template>\n}\n","import { withPluginApi } from \"discourse/lib/plugin-api\";\nimport Carousel from \"../components/carousel\";\n\nexport default {\n  name: \"carousel-api\",\n\n  initialize() {\n    withPluginApi((api) => {\n      const carouselComponents = new Map();\n\n      carouselComponents.set(\"carousel\", Carousel);\n\n      api.getCarouselComponent = (type = \"carousel\") => {\n        return carouselComponents.get(type);\n      };\n\n      api.registerCarouselComponent = (name, component) => {\n        carouselComponents.set(name, component);\n      };\n\n      api.carouselComponents = carouselComponents;\n    });\n  },\n};\n","import { apiInitializer } from \"discourse/lib/api\";\n\nexport default apiInitializer((api) => {\n  // Your code here    \n});","import Component from \"@glimmer/component\";\nimport { action } from \"@ember/object\";\nimport didInsert from \"@ember/render-modifiers/modifiers/did-insert\";\nimport didUpdate from \"@ember/render-modifiers/modifiers/did-update\";\nimport { service } from \"@ember/service\";\nimport { defaultHomepage } from \"discourse/lib/utilities\";\nimport Carousel from \"../../components/carousel\";\n\nexport default class CustomTopicLists extends Component {\n  @service router;\n  @service discovery;\n  @service featuredTopics;\n\n  @action\n  loadTopicsWhenReady() {\n    // Load topics after component is rendered to avoid circular dependency\n    const category = this.currentCategory;\n    this.featuredTopics.getFeaturedTopics(category);\n  }\n  \n  get currentCategory() {\n    // Only apply category filtering if the setting is enabled\n    if (!settings.filter_by_category) {\n      return null;\n    }\n    \n    // Use Discourse's discovery service for proper category detection\n    // This handles all the complex routing logic for us\n    if (this.discovery.onDiscoveryRoute) {\n      return this.discovery.category;\n    }\n    \n    // If not on a discovery route, don't filter by category\n    return null;\n  }\n\n  get showHere() {\n    if (settings.show_on === \"all\") {\n      return true;\n    }\n\n    if (settings.show_on === \"discovery\") {\n      return this.router.currentRouteName.indexOf(\"discovery\") > -1;\n    }\n\n    if (settings.show_on === \"homepage\") {\n      return this.router.currentRouteName === `discovery.${defaultHomepage()}`;\n    }\n\n    if (settings.show_on === \"hidden\") {\n      return false;\n    }\n  }\n\n  <template>\n    {{#if this.showHere}}\n      <div \n        {{didInsert this.loadTopicsWhenReady}}\n        {{didUpdate this.loadTopicsWhenReady this.router.currentRouteName}}\n      >\n        <Carousel\n          @topics={{this.featuredTopics.topics}}\n          @isLoading={{this.featuredTopics.isLoading}}\n        />\n      </div>\n    {{/if}}\n  </template>\n}\n","export default function range(start, end) {\n  if (typeof start !== \"number\" || typeof end !== \"number\" || start >= end) {\n    return [];\n  }\n  return Array.from({ length: end - start }, (_, i) => start + i);\n}\n","import { tracked } from \"@glimmer/tracking\";\nimport { action } from \"@ember/object\";\nimport Service, { service } from \"@ember/service\";\n\nexport default class FeaturedTopicsService extends Service {\n  @service store;\n\n  @tracked topics = [];\n  @tracked isLoading = false;\n  @tracked hasError = false;\n\n  // Store multiple loading promises and cache by key to avoid conflicts\n  _loadingPromises = new Map();\n  _topicsCache = new Map();\n\n  /**\n   * Load featured topics based on the configured tag and settings\n   * @param {Object|null} category - Optional category to filter by\n   * @param {string|null} tagName - Optional custom tag name, defaults to settings.featured_tag\n   * @returns {Promise<Array>} Array of featured topics\n   */\n  @action\n  async loadFeaturedTopics(category = null, tagName = null) {\n    const tag = tagName || settings.featured_tag;\n    const cacheKey = `${tag}_${category?.id || 'all'}`;\n    \n    // If already loading the same request, return the existing promise\n    if (this._loadingPromises.has(cacheKey)) {\n      return this._loadingPromises.get(cacheKey);\n    }\n\n    // If we have cached topics, return them (for default tag case)\n    if (this._topicsCache.has(cacheKey)) {\n      const cachedTopics = this._topicsCache.get(cacheKey);\n      // For the default tag, also update the main topics property for backward compatibility\n      if (tag === settings.featured_tag) {\n        this.topics = cachedTopics;\n      }\n      return cachedTopics;\n    }\n\n    const promise = this._performLoad(category, tag, cacheKey);\n    this._loadingPromises.set(cacheKey, promise);\n    return promise;\n  }\n\n  async _performLoad(category = null, tagName = null, cacheKey = null) {\n    try {\n      this.isLoading = true;\n      this.hasError = false;\n\n      const filter = {\n        filter: \"latest\",\n        params: {\n          tags: tagName || settings.featured_tag,\n        },\n      };\n      \n      // Add category filtering if enabled and category is provided\n      if (settings.filter_by_category && category) {\n        filter.params.category = category.id;\n      }\n\n      const topicList = await this.store.findFiltered(\"topicList\", filter);\n      const fetchedTopics = topicList.topics.slice(0, settings.topics_length);\n      \n      // Cache the results\n      if (cacheKey) {\n        this._topicsCache.set(cacheKey, fetchedTopics);\n      }\n      \n      // For the default tag, also update the main topics property for backward compatibility\n      if ((tagName || settings.featured_tag) === settings.featured_tag) {\n        this.topics = fetchedTopics;\n      }\n      \n      return fetchedTopics;\n    } catch (error) {\n      this.hasError = true;\n      // Only clear main topics if this was for the default tag\n      if ((tagName || settings.featured_tag) === settings.featured_tag) {\n        this.topics = [];\n      }\n      // eslint-disable-next-line no-console\n      console.error(\"FeaturedTopicsService: Failed to load topics\", error);\n      return [];\n    } finally {\n      this.isLoading = false;\n      // Remove the loading promise for this specific request\n      if (cacheKey) {\n        this._loadingPromises.delete(cacheKey);\n      }\n    }\n  }\n\n  /**\n   * Get cached topics if available, otherwise load them\n   * @param {Object|null} category - Optional category to filter by\n   * @param {string|null} tagName - Optional custom tag name, defaults to settings.featured_tag\n   * @returns {Promise<Array>} Array of featured topics\n   */\n  @action\n  async getFeaturedTopics(category = null, tagName = null) {\n    return await this.loadFeaturedTopics(category, tagName);\n  }\n\n  /**\n   * Refresh topics (force reload)\n   * @param {Object|null} category - Optional category to filter by\n   * @param {string|null} tagName - Optional custom tag name, defaults to settings.featured_tag\n   * @returns {Promise<Array>} Array of featured topics\n   */\n  @action\n  async refreshFeaturedTopics(category = null, tagName = null) {\n    const tag = tagName || settings.featured_tag;\n    const cacheKey = `${tag}_${category?.id || 'all'}`;\n    \n    // Clear specific cache entry\n    this._topicsCache.delete(cacheKey);\n    this._loadingPromises.delete(cacheKey);\n    \n    // Clear main topics if this is for the default tag\n    if (tag === settings.featured_tag) {\n      this.topics = [];\n    }\n    \n    this.hasError = false;\n    return await this.loadFeaturedTopics(category, tagName);\n  }\n\n  /**\n   * Get topics for a specific tag/category combination (synchronous)\n   * @param {Object|null} category - Optional category to filter by\n   * @param {string|null} tagName - Optional custom tag name, defaults to settings.featured_tag\n   * @returns {Array} Array of topics (empty if not loaded yet)\n   */\n  getTopicsForTag(category = null, tagName = null) {\n    const tag = tagName || settings.featured_tag;\n    const cacheKey = `${tag}_${category?.id || 'all'}`;\n    \n    // Return cached topics if available\n    if (this._topicsCache.has(cacheKey)) {\n      return this._topicsCache.get(cacheKey);\n    }\n    \n    // For default tag, fall back to main topics property\n    if (tag === settings.featured_tag) {\n      return this.topics || [];\n    }\n    \n    // No topics available yet\n    return [];\n  }\n\n  /**\n   * Clear cached topics\n   */\n  @action\n  clearTopics() {\n    this.topics = [];\n    this.hasError = false;\n    this._loadingPromises.clear();\n    this._topicsCache.clear();\n  }\n}","import * as Mod1 from \"./discourse/api-initializers/carousel-api\";\nimport * as Mod2 from \"./discourse/api-initializers/theme-initializer\";\nimport * as Mod3 from \"./discourse/components/carousel\";\nimport * as Mod4 from \"./discourse/connectors/above-main-container/carousel.gjs\";\nimport * as Mod5 from \"./discourse/helpers/range\";\nimport * as Mod6 from \"./discourse/lib/image-color-utils\";\nimport * as Mod7 from \"./discourse/services/featured-topics\";\nconst compatModules = {\n  \"discourse/api-initializers/carousel-api\": Mod1,\n  \"discourse/api-initializers/theme-initializer\": Mod2,\n  \"discourse/components/carousel\": Mod3,\n  \"discourse/connectors/above-main-container/carousel\": Mod4,\n  \"discourse/helpers/range\": Mod5,\n  \"discourse/lib/image-color-utils\": Mod6,\n  \"discourse/services/featured-topics\": Mod7,\n};\nexport { compatModules };\nexport default compatModules;\n"],"names":["settings","getObjectForTheme","async","extractDominantColor","imageUrl","options","config","regions","minBrightness","Promise","resolve","reject","canvas","document","createElement","context","getContext","willReadFrequently","img","Image","crossOrigin","src","onerror","Error","onload","width","naturalWidth","height","naturalHeight","drawImage","dominantColor","imgData","regionWidth","Math","floor","regionHeight","highestSaturation","bestRegionColor","r","g","b","regionX","regionY","regionResult","analyzeRegion","avgSaturation","avgColor","brightness","calculateBrightness","color","saturation","analyzeDominantColor","getImageData","data","error","imgWidth","startX","startY","regionSaturation","regionPixelCount","regionColorSum","y","x","index","calculateSaturation","max","min","generateThemeColors","isLight","accent","text","invert","background","applyThemeColors","element","prefix","themeColors","style","setProperty","extractAndApplyImageTheme","targetElement","console","warn","Carousel","Component","dt7948","this","prototype","service","featuredTopics","i","tracked","containerWidth","currentIndex","topics_per_slide","visibleCount","autoplayInterval","carouselElement","static","observeResize","modifierFn","debounceTimer","resizeObserver","ResizeObserver","entries","cancel","discourseLater","contentRect","updateVisibleCount","observe","disconnect","autoplayEnabled","autoplay","shouldAutoplay","hasMoreTopics","isLoading","topics","length","args","tagName","getTopicsForTag","category","undefined","currentTopic","offset","degrade","BREAKPOINT_MEDIUM","BREAKPOINT_SMALL","n","action","storeCarouselElement","loadTopicsByTag","getFeaturedTopics","visibleOffsets","Array","from","_","setupAutoplay","startAutoplay","stopAutoplay","isCarousel","restartAutoplay","setInterval","nextIndex","clearInterval","handleMouseEnter","handleMouseLeave","updateCarouselClass","direction","classList","toggle","animateCarouselChange","prevIndex","changeIndex","callback","computedHeight","window","getComputedStyle","add","remove","safeCarouselHeight","styles","image_height","image_aspect_ratio","display_images","htmlSafe","repliesCount","posts","headerText","header","subheaderText","subheader","handleImageLoad","event","target","setComponentTemplate","createTemplateFactory","id","block","moduleName","scope","didInsert","didUpdate","on","DButton","ConditionalLoadingSpinner","and","or","replaceEmoji","categoryLink","discourseTags","get","avatar","icon","number","gt","formatDate","fn","isStrictMode","carouselApi","name","initialize","withPluginApi","api","carouselComponents","Map","set","getCarouselComponent","type","registerCarouselComponent","component","themeInitializer","apiInitializer","CustomTopicLists","router","discovery","loadTopicsWhenReady","currentCategory","filter_by_category","onDiscoveryRoute","showHere","show_on","currentRouteName","indexOf","defaultHomepage","start","end","FeaturedTopicsService","Service","store","hasError","_loadingPromises","_topicsCache","loadFeaturedTopics","tag","featured_tag","cacheKey","has","cachedTopics","promise","_performLoad","filter","params","tags","fetchedTopics","findFiltered","slice","topics_length","delete","refreshFeaturedTopics","clearTopics","clear","compatModules","Mod1","Mod2","Mod3","Mod4","Mod5","Mod6"],"mappings":"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"}