var/cache/dev/twig/01/01e79143cf092d4c3d60a2ae714410cc.php line 40

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\SandboxExtension;
  6. use Twig\Markup;
  7. use Twig\Sandbox\SecurityError;
  8. use Twig\Sandbox\SecurityNotAllowedTagError;
  9. use Twig\Sandbox\SecurityNotAllowedFilterError;
  10. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  11. use Twig\Source;
  12. use Twig\Template;
  13. /* index.twig */
  14. class __TwigTemplate_1288a8c934165619861e7a1b14d9faa4 extends \Eccube\Twig\Template
  15. {
  16.     private $source;
  17.     private $macros = [];
  18.     public function __construct(Environment $env)
  19.     {
  20.         parent::__construct($env);
  21.         $this->source $this->getSourceContext();
  22.         $this->blocks = [
  23.             'main' => [$this'block_main'],
  24.             'stylesheet' => [$this'block_stylesheet'],
  25.             'javascript' => [$this'block_javascript'],
  26.         ];
  27.     }
  28.     protected function doGetParent(array $context)
  29.     {
  30.         // line 1
  31.         return "default_frame.twig";
  32.     }
  33.     protected function doDisplay(array $context, array $blocks = [])
  34.     {
  35.         $macros $this->macros;
  36.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  37.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""index.twig"));
  38.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  39.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""index.twig"));
  40.         // line 2
  41.         $context["body_class"] = "front_page";
  42.         // line 1
  43.         $this->parent $this->loadTemplate("default_frame.twig""index.twig"1);
  44.         $this->parent->display($contextarray_merge($this->blocks$blocks));
  45.         
  46.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  47.         
  48.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  49.     }
  50.     // line 3
  51.     public function block_main($context, array $blocks = [])
  52.     {
  53.         $macros $this->macros;
  54.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  55.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""main"));
  56.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  57.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""main"));
  58.         // line 4
  59.         echo "<div class=\"mycarousel-wrapper\">
  60.     <div class=\"mycarousel-slider\">
  61.         ";
  62.         // line 7
  63.         echo "        ";
  64.         $context["pc_images"] = [=> "main-visual.jpg"=> "main-visual.jpg"=> "main-visual.jpg"];
  65.         // line 12
  66.         echo "        
  67.         ";
  68.         // line 14
  69.         echo "        ";
  70.         $context["sp_images"] = [=> "sp-topImages.jpg"=> "sp-topImages.jpg"=> "sp-topImages.jpg"];
  71.         // line 19
  72.         echo "        
  73.         ";
  74.         // line 21
  75.         echo "        ";
  76.         $context["display_images"] = [=> 0=> 1=> 2];
  77.         // line 22
  78.         echo "        
  79.         ";
  80.         // line 23
  81.         $context['_parent'] = $context;
  82.         $context['_seq'] = twig_ensure_traversable((isset($context["display_images"]) || array_key_exists("display_images"$context) ? $context["display_images"] : (function () { throw new RuntimeError('Variable "display_images" does not exist.'23$this->source); })()));
  83.         foreach ($context['_seq'] as $context["_key"] => $context["index"]) {
  84.             // line 24
  85.             echo "            <div class=\"mycarousel-slide\">
  86.                 <img class=\"desktop-image\" src=\"";
  87.             // line 25
  88.             echo twig_escape_filter($this->env$this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl(("/html/user_data/ContentImg/" twig_get_attribute($this->env$this->source, (isset($context["pc_images"]) || array_key_exists("pc_images"$context) ? $context["pc_images"] : (function () { throw new RuntimeError('Variable "pc_images" does not exist.'25$this->source); })()), $context["index"], [], "array"falsefalsefalse25))), "html"nulltrue);
  89.             echo "\" alt=\"スライド画像\">
  90.                 <img class=\"mobile-image\" src=\"";
  91.             // line 26
  92.             echo twig_escape_filter($this->env$this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl(("/html/user_data/ContentImg/" twig_get_attribute($this->env$this->source, (isset($context["sp_images"]) || array_key_exists("sp_images"$context) ? $context["sp_images"] : (function () { throw new RuntimeError('Variable "sp_images" does not exist.'26$this->source); })()), $context["index"], [], "array"falsefalsefalse26))), "html"nulltrue);
  93.             echo "\" alt=\"スライド画像\">
  94.             </div>
  95.         ";
  96.         }
  97.         $_parent $context['_parent'];
  98.         unset($context['_seq'], $context['_iterated'], $context['_key'], $context['index'], $context['_parent'], $context['loop']);
  99.         $context array_intersect_key($context$_parent) + $_parent;
  100.         // line 29
  101.         echo "    </div>
  102. </div>
  103. ";
  104.         
  105.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  106.         
  107.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  108.     }
  109.     // line 32
  110.     public function block_stylesheet($context, array $blocks = [])
  111.     {
  112.         $macros $this->macros;
  113.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  114.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheet"));
  115.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  116.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""stylesheet"));
  117.         // line 33
  118.         echo "<style>
  119. /* slickのデフォルト黒丸(before擬似要素)を無効化 */
  120. .mycarousel-slider .slick-dots li button::before {
  121.     display: none;
  122.     content: '';
  123. }
  124. .slick-dots li {
  125.     position:unset;
  126.     display: inline-block;
  127.     width: 20px;
  128.     height: 20px;
  129.     margin: 0 5px;
  130.     padding: 0;
  131.     cursor: pointer;
  132. }
  133. .mycarousel-slider .slick-dots li {
  134.     width: 10px;
  135.     height: 10px;
  136. }
  137. .mycarousel-slider .slick-dots li button {
  138.     width: 100%;
  139.     height: 100%;
  140.     padding: 0;
  141.     border: none;
  142.     border-radius: 50%;
  143.     background-color: #ccc;
  144.     opacity: 0.7;
  145.     transition: all 0.3s ease;
  146.     font-size: 0;
  147.     cursor: pointer;
  148. }
  149. .mycarousel-slider .slick-dots li.slick-active button {
  150.     background-color: #b8860b;
  151.     transform: scale(1.3);
  152.     opacity: 1;
  153. }
  154. /* フルワイドの外枠 */
  155. .mycarousel-wrapper {
  156.     width: 100vw;
  157.     max-width: none;
  158.     margin-left: calc(-50vw + 50%);
  159.     margin-right: calc(-50vw + 50%);
  160.     overflow: hidden;
  161.     padding: 0;
  162.     /* 初期化時のちらつき防止 */
  163.     visibility: hidden;
  164. }
  165. /* slickのトラック修正 */
  166. .slick-track {
  167.     display: flex !important;
  168.     align-items: center;
  169. }
  170. .slick-slide {
  171.     padding: 0 !important;
  172.     margin: 0 !important;
  173. }
  174. /* スライド本体(動的高さ対応) */
  175. .mycarousel-slide {
  176.     box-sizing: border-box;
  177.     padding: 0 !important;
  178.     margin: 0 !important;
  179.     position: relative;
  180.     transition: all 0.5s ease;
  181.     overflow: hidden;
  182.     /* 高さは動的に設定される */
  183.     height: 60vh; /* 初期値:JavaScript で調整される */
  184. }
  185. /* 画像の基本スタイル */
  186. .desktop-image,
  187. .mobile-image {
  188.     position: absolute;
  189.     top: 0;
  190.     left: 0;
  191.     width: 100%;
  192.     height: 100%;
  193.     transition: all 0.5s ease;
  194.     /* object-fit は JavaScript で動的に調整 */
  195.     object-fit: contain;
  196. }
  197. /* デスクトップ時のスタイル(768pxより大きい) */
  198. @media (min-width: 769px) {
  199.     .desktop-image {
  200.         display: block !important;
  201.     }
  202.     .mobile-image {
  203.         display: none !important;
  204.     }
  205. }
  206. /* モバイル時のスタイル(768px以下) */
  207. @media (max-width: 768px) {
  208.     .mycarousel-wrapper {
  209.         width: 100vw;
  210.         margin-left: calc(-50vw + 50%);
  211.         margin-right: calc(-50vw + 50%);
  212.     }
  213.     
  214.     .mycarousel-slide {
  215.         width: 100vw !important;
  216.         height: auto !important;
  217.         padding: 0 !important;
  218.         margin: 0 !important;
  219.         opacity: 1 !important;
  220.         filter: none !important;
  221.     }
  222.     .desktop-image {
  223.         display: none !important;
  224.     }
  225.     
  226.     .mobile-image {
  227.         display: block !important;
  228.         position: relative !important;
  229.         width: 100% !important;
  230.         height: auto !important;
  231.         object-fit: contain !important;
  232.         filter: brightness(1) contrast(1) !important;
  233.     }
  234. }
  235. /* 左右の画像を暗くするエフェクト(デスクトップのみ) */
  236. @media (min-width: 769px) {
  237.     .mycarousel-slide.side-slide {
  238.         opacity: 0.6;
  239.     }
  240.     .mycarousel-slide.side-slide .desktop-image {
  241.         filter: brightness(0.7) contrast(0.9);
  242.     }
  243.     .mycarousel-slide.center-slide {
  244.         opacity: 1;
  245.     }
  246.     .mycarousel-slide.center-slide .desktop-image {
  247.         filter: brightness(1) contrast(1);
  248.     }
  249.     .mycarousel-slide.side-slide:hover {
  250.         opacity: 0.8;
  251.         transform: scale(1.02);
  252.     }
  253.     .mycarousel-slide.side-slide:hover .desktop-image {
  254.         filter: brightness(0.85) contrast(0.95);
  255.     }
  256. }
  257. /* 動的高さ調整用のユーティリティクラス */
  258. .dynamic-fit-contain {
  259.     object-fit: contain;
  260. }
  261. .dynamic-fit-cover {
  262.     object-fit: cover;
  263. }
  264. </style>
  265. ";
  266.         
  267.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  268.         
  269.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  270.     }
  271.     // line 190
  272.     public function block_javascript($context, array $blocks = [])
  273.     {
  274.         $macros $this->macros;
  275.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  276.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascript"));
  277.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  278.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascript"));
  279.         // line 191
  280.         echo "<script>
  281. \$(function() {
  282.     // 動的レスポンシブ設定
  283.     const RESPONSIVE_CONFIG = {
  284.         desktop: {
  285.             targetAspectRatio: 16/9,
  286.             minHeight: '30vh',
  287.             maxHeight: '60vh',
  288.             marginThreshold: 0.15
  289.         },
  290.         mobile: {
  291.             targetAspectRatio: 4/3,
  292.             minHeight: '35vh',
  293.             maxHeight: '85vh',
  294.             marginThreshold: 0.12
  295.         }
  296.     };
  297.     let isInitialized = false;
  298.     let currentImages = [];
  299.     // 画面幅に応じた動的centerPadding計算
  300.     function calculateCenterPadding() {
  301.         const windowWidth = \$(window).width();
  302.         let padding;
  303.         
  304.         // 画面幅に応じてcenterPaddingを計算(調整可能な閾値)
  305.         if (windowWidth <= 768) {
  306.             // モバイル: 余白なし
  307.             padding = '0';
  308.         } else if (windowWidth <= 1024) {
  309.             // タブレット: 小さめの余白
  310.             padding = '8vw';
  311.         } else if (windowWidth <= 1200) {
  312.             // 小型デスクトップ: 中程度の余白
  313.             padding = '12vw';
  314.         }else if (windowWidth <= 1440) {
  315.             // 小型デスクトップ: 中程度の余白
  316.             padding = '15vw';
  317.         
  318.         } else if (windowWidth <= 1920) {
  319.             // 標準デスクトップ: やや大きめの余白
  320.             padding = '20vw';
  321.         } else {
  322.             // 大型ディスプレイ: 最大余白を制限
  323.             padding = '25vw';
  324.         }
  325.         
  326.         return padding;
  327.     }
  328.     // centerPaddingを動的に更新する関数
  329.     function updateCenterPadding() {
  330.         const newPadding = calculateCenterPadding();
  331.         const windowWidth = \$(window).width();
  332.         
  333.         // モバイルはcenterMode自体を無効にする
  334.         const centerModeEnabled = windowWidth > 768;
  335.         
  336.         if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
  337.             \$('.mycarousel-slider').slick('slickSetOption', 'centerMode', centerModeEnabled, false);
  338.             \$('.mycarousel-slider').slick('slickSetOption', 'centerPadding', newPadding, true);
  339.         }
  340.     }
  341.     // 現在のデバイスに応じた画像を取得
  342.     function getCurrentImages() {
  343.         const isMobile = \$(window).width() <= 768;
  344.         return isMobile ? \$('.mobile-image') : \$('.desktop-image');
  345.     }
  346.     // 画像プリロード関数
  347.     function preloadImages() {
  348.         return new Promise((resolve) => {
  349.             const images = getCurrentImages();
  350.             let loadedCount = 0;
  351.             const totalImages = images.length;
  352.             if (totalImages === 0) {
  353.                 resolve();
  354.                 return;
  355.             }
  356.             images.each(function() {
  357.                 const img = this;
  358.                 
  359.                 if (img.complete && img.naturalWidth > 0) {
  360.                     loadedCount++;
  361.                     if (loadedCount >= totalImages) {
  362.                         resolve();
  363.                     }
  364.                 } else {
  365.                     \$(img).on('load error', function() {
  366.                         loadedCount++;
  367.                         if (loadedCount >= totalImages) {
  368.                             resolve();
  369.                         }
  370.                     });
  371.                     
  372.                     // 強制的に再読み込みをトリガー(キャッシュ対策)
  373.                     if (!img.src) {
  374.                         img.src = img.getAttribute('src');
  375.                     }
  376.                 }
  377.             });
  378.         });
  379.     }
  380.     // スライダー初期化(動的centerPadding対応版)
  381.     function initializeSlider() {
  382.         if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
  383.             \$('.mycarousel-slider').slick('unslick');
  384.         }
  385.         const initialPadding = calculateCenterPadding();
  386.         const windowWidth = \$(window).width();
  387.         const centerModeEnabled = windowWidth > 768;
  388.         \$('.mycarousel-slider').slick({
  389.             centerMode: centerModeEnabled,
  390.             centerPadding: initialPadding,
  391.             slidesToShow: 1,
  392.             autoplay: false, // 初期化時は自動再生を無効にして安定性を確保
  393.             autoplaySpeed: 5000,
  394.             arrows: true,
  395.             dots: true,
  396.             adaptiveHeight: false,
  397.             fade: false,
  398.             speed: 300
  399.             // responsive設定は削除(動的制御に切り替え)
  400.         });
  401.         // スライド変更時にクラスを更新
  402.         \$('.mycarousel-slider').on('afterChange', function(event, slick, currentSlide) {
  403.             updateSlideClasses();
  404.         });
  405.     }
  406.     // 動的な表示最適化メイン関数
  407.     function optimizeCarouselDisplay() {
  408.         const isMobile = \$(window).width() <= 768;
  409.         const config = isMobile ? RESPONSIVE_CONFIG.mobile : RESPONSIVE_CONFIG.desktop;
  410.         const \$currentImages = getCurrentImages();
  411.         
  412.         if (\$currentImages.length === 0) return;
  413.         // モバイル時は簡単な設定にする
  414.         if (isMobile) {
  415.             // モバイル時:width 100vw、height auto
  416.             \$('.mycarousel-slide').css({
  417.                 'height': 'auto',
  418.                 'width': '100vw'
  419.             });
  420.             \$currentImages.css({
  421.                 'width': '100%',
  422.                 'height': 'auto',
  423.                 'object-fit': 'contain',
  424.                 'position': 'relative'
  425.             });
  426.             
  427.             // 初期化完了後に自動再生を開始
  428.             if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
  429.                 \$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
  430.             }
  431.             return;
  432.         }
  433.         const \$firstImage = \$currentImages.filter(':visible').first();
  434.         if (\$firstImage.length === 0 || !\$firstImage[0].complete || !\$firstImage[0].naturalWidth) {
  435.             return;
  436.         }
  437.         const imageWidth = \$firstImage[0].naturalWidth;
  438.         const imageHeight = \$firstImage[0].naturalHeight;
  439.         const imageAspectRatio = imageWidth / imageHeight;
  440.         
  441.         const containerWidth = \$('.mycarousel-wrapper').width();
  442.         const containerAspectRatio = config.targetAspectRatio;
  443.         
  444.         const maxRenderWidth = Math.min(imageWidth, containerWidth);
  445.         const maxRenderHeight = maxRenderWidth / imageAspectRatio;
  446.         
  447.         const viewportMinHeightPx = parseFloat(config.minHeight) * \$(window).height() / 100;
  448.         const viewportMaxHeightPx = parseFloat(config.maxHeight) * \$(window).height() / 100;
  449.         
  450.         let optimalHeight;
  451.         let objectFitMode = 'contain';
  452.         const aspectRatioDiff = Math.abs(imageAspectRatio - containerAspectRatio) / containerAspectRatio;
  453.         if (maxRenderHeight <= viewportMaxHeightPx && maxRenderHeight >= viewportMinHeightPx) {
  454.             optimalHeight = maxRenderHeight;
  455.         } else if (maxRenderHeight > viewportMaxHeightPx) {
  456.             if (aspectRatioDiff <= config.marginThreshold) {
  457.                 optimalHeight = viewportMaxHeightPx;
  458.             } else {
  459.                 optimalHeight = Math.min(containerWidth / imageAspectRatio, viewportMaxHeightPx);
  460.             }
  461.         } else {
  462.             if (maxRenderHeight < viewportMinHeightPx) {
  463.                 const scaleUpLimit = Math.min(2.0, viewportMinHeightPx / maxRenderHeight);
  464.                 if (scaleUpLimit <= 1.5) {
  465.                     optimalHeight = viewportMinHeightPx;
  466.                 } else {
  467.                     optimalHeight = maxRenderHeight;
  468.                 }
  469.             } else {
  470.                 optimalHeight = maxRenderHeight;
  471.             }
  472.         }
  473.         // 最終的な制限適用
  474.         optimalHeight = Math.max(viewportMinHeightPx, Math.min(viewportMaxHeightPx, optimalHeight));
  475.         // 画像の品質を考慮したobject-fit調整
  476.         const renderScale = optimalHeight / maxRenderHeight;
  477.         if (renderScale > 1.2) {
  478.             objectFitMode = 'contain';
  479.         } else {
  480.             objectFitMode = 'contain';
  481.         }
  482.         // スタイル適用(デスクトップのみ)
  483.         \$('.mycarousel-slide').css('height', optimalHeight + 'px');
  484.         \$currentImages.css({
  485.             'object-fit': objectFitMode,
  486.             'image-rendering': renderScale > 1.1 ? 'smooth' : 'auto'
  487.         });
  488.         // 初期化完了後に自動再生を開始
  489.         if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
  490.             \$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
  491.         }
  492.     }
  493.     // スライドのクラスを更新する関数
  494.     function updateSlideClasses() {
  495.         \$('.mycarousel-slide').removeClass('center-slide side-slide');
  496.         
  497.         if (\$(window).width() > 768) {
  498.             \$('.slick-center .mycarousel-slide').addClass('center-slide');
  499.             \$('.slick-slide:not(.slick-center) .mycarousel-slide').addClass('side-slide');
  500.         } else {
  501.             \$('.mycarousel-slide').addClass('center-slide');
  502.         }
  503.     }
  504.     async function initialize() {
  505.         try {
  506.             // カルーセルを一時的に非表示にしてちらつき防止
  507.             \$('.mycarousel-wrapper').css('visibility', 'hidden');
  508.             
  509.             await preloadImages();
  510.             
  511.             initializeSlider();
  512.             
  513.             optimizeCarouselDisplay();
  514.             
  515.             updateSlideClasses();
  516.             
  517.             isInitialized = true;
  518.             
  519.             // 6. 少し待ってから表示(slickの初期化完了を確実にする)
  520.             setTimeout(() => {
  521.                 \$('.mycarousel-wrapper').css('visibility', 'visible');
  522.                 // 初期化後にもう一度表示を最適化
  523.                 optimizeCarouselDisplay();
  524.                 updateSlideClasses();
  525.             }, 50);
  526.             
  527.             console.log('Carousel initialized successfully');
  528.             
  529.         } catch (error) {
  530.             console.error('Carousel initialization failed:', error);
  531.             // エラー時も表示を戻す
  532.             \$('.mycarousel-wrapper').css('visibility', 'visible');
  533.         }
  534.     }
  535.     let resizeTimer;
  536.     \$(window).on('resize', function() {
  537.         clearTimeout(resizeTimer);
  538.         resizeTimer = setTimeout(async () => {
  539.             // centerPaddingを動的に更新
  540.             updateCenterPadding();
  541.             
  542.             // デバイス切り替わり時は再初期化
  543.             const newImages = getCurrentImages();
  544.             const imagesSwitched = !currentImages.length || 
  545.                 newImages.length !== currentImages.length ||
  546.                 newImages[0] !== currentImages[0];
  547.             
  548.             if (imagesSwitched) {
  549.                 currentImages = newImages;
  550.                 await preloadImages();
  551.             }
  552.             
  553.             optimizeCarouselDisplay();
  554.             updateSlideClasses();
  555.         }, 200);
  556.     });
  557.     
  558.     \$(document).ready(function() {
  559.         currentImages = getCurrentImages();
  560.         initialize();
  561.     });
  562.     
  563.     \$(window).on('load', function() {
  564.         if (!isInitialized) {
  565.             initialize();
  566.         }
  567.     });
  568. });
  569. </script>
  570. ";
  571.         
  572.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  573.         
  574.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  575.     }
  576.     public function getTemplateName()
  577.     {
  578.         return "index.twig";
  579.     }
  580.     public function isTraitable()
  581.     {
  582.         return false;
  583.     }
  584.     public function getDebugInfo()
  585.     {
  586.         return array (  313 => 191,  303 => 190,  137 => 33,  127 => 32,  115 => 29,  106 => 26,  102 => 25,  99 => 24,  95 => 23,  92 => 22,  89 => 21,  86 => 19,  83 => 14,  80 => 12,  77 => 7,  73 => 4,  63 => 3,  52 => 1,  50 => 2,  37 => 1,);
  587.     }
  588.     public function getSourceContext()
  589.     {
  590.         return new Source("{% extends 'default_frame.twig' %}
  591. {% set body_class = 'front_page' %}
  592. {% block main %}
  593. <div class=\"mycarousel-wrapper\">
  594.     <div class=\"mycarousel-slider\">
  595.         {# PC用画像リスト main-visual.jpg #}
  596.         {% set pc_images = [
  597.             'main-visual.jpg',
  598.             'main-visual.jpg',
  599.             'main-visual.jpg'
  600.         ] %}
  601.         
  602.         {# SP用画像リスト sp-topImages.jpg #}
  603.         {% set sp_images = [
  604.         'sp-topImages.jpg',
  605.         'sp-topImages.jpg',
  606.         'sp-topImages.jpg'
  607.         ] %}
  608.         
  609.         {# 実際に表示する画像を選択(0から始まるインデックス番号で指定) #}
  610.         {% set display_images = [0,1,2] %}
  611.         
  612.         {% for index in display_images %}
  613.             <div class=\"mycarousel-slide\">
  614.                 <img class=\"desktop-image\" src=\"{{ asset('/html/user_data/ContentImg/' ~ pc_images[index]) }}\" alt=\"スライド画像\">
  615.                 <img class=\"mobile-image\" src=\"{{ asset('/html/user_data/ContentImg/' ~ sp_images[index]) }}\" alt=\"スライド画像\">
  616.             </div>
  617.         {% endfor %}
  618.     </div>
  619. </div>
  620. {% endblock %}
  621. {% block stylesheet %}
  622. <style>
  623. /* slickのデフォルト黒丸(before擬似要素)を無効化 */
  624. .mycarousel-slider .slick-dots li button::before {
  625.     display: none;
  626.     content: '';
  627. }
  628. .slick-dots li {
  629.     position:unset;
  630.     display: inline-block;
  631.     width: 20px;
  632.     height: 20px;
  633.     margin: 0 5px;
  634.     padding: 0;
  635.     cursor: pointer;
  636. }
  637. .mycarousel-slider .slick-dots li {
  638.     width: 10px;
  639.     height: 10px;
  640. }
  641. .mycarousel-slider .slick-dots li button {
  642.     width: 100%;
  643.     height: 100%;
  644.     padding: 0;
  645.     border: none;
  646.     border-radius: 50%;
  647.     background-color: #ccc;
  648.     opacity: 0.7;
  649.     transition: all 0.3s ease;
  650.     font-size: 0;
  651.     cursor: pointer;
  652. }
  653. .mycarousel-slider .slick-dots li.slick-active button {
  654.     background-color: #b8860b;
  655.     transform: scale(1.3);
  656.     opacity: 1;
  657. }
  658. /* フルワイドの外枠 */
  659. .mycarousel-wrapper {
  660.     width: 100vw;
  661.     max-width: none;
  662.     margin-left: calc(-50vw + 50%);
  663.     margin-right: calc(-50vw + 50%);
  664.     overflow: hidden;
  665.     padding: 0;
  666.     /* 初期化時のちらつき防止 */
  667.     visibility: hidden;
  668. }
  669. /* slickのトラック修正 */
  670. .slick-track {
  671.     display: flex !important;
  672.     align-items: center;
  673. }
  674. .slick-slide {
  675.     padding: 0 !important;
  676.     margin: 0 !important;
  677. }
  678. /* スライド本体(動的高さ対応) */
  679. .mycarousel-slide {
  680.     box-sizing: border-box;
  681.     padding: 0 !important;
  682.     margin: 0 !important;
  683.     position: relative;
  684.     transition: all 0.5s ease;
  685.     overflow: hidden;
  686.     /* 高さは動的に設定される */
  687.     height: 60vh; /* 初期値:JavaScript で調整される */
  688. }
  689. /* 画像の基本スタイル */
  690. .desktop-image,
  691. .mobile-image {
  692.     position: absolute;
  693.     top: 0;
  694.     left: 0;
  695.     width: 100%;
  696.     height: 100%;
  697.     transition: all 0.5s ease;
  698.     /* object-fit は JavaScript で動的に調整 */
  699.     object-fit: contain;
  700. }
  701. /* デスクトップ時のスタイル(768pxより大きい) */
  702. @media (min-width: 769px) {
  703.     .desktop-image {
  704.         display: block !important;
  705.     }
  706.     .mobile-image {
  707.         display: none !important;
  708.     }
  709. }
  710. /* モバイル時のスタイル(768px以下) */
  711. @media (max-width: 768px) {
  712.     .mycarousel-wrapper {
  713.         width: 100vw;
  714.         margin-left: calc(-50vw + 50%);
  715.         margin-right: calc(-50vw + 50%);
  716.     }
  717.     
  718.     .mycarousel-slide {
  719.         width: 100vw !important;
  720.         height: auto !important;
  721.         padding: 0 !important;
  722.         margin: 0 !important;
  723.         opacity: 1 !important;
  724.         filter: none !important;
  725.     }
  726.     .desktop-image {
  727.         display: none !important;
  728.     }
  729.     
  730.     .mobile-image {
  731.         display: block !important;
  732.         position: relative !important;
  733.         width: 100% !important;
  734.         height: auto !important;
  735.         object-fit: contain !important;
  736.         filter: brightness(1) contrast(1) !important;
  737.     }
  738. }
  739. /* 左右の画像を暗くするエフェクト(デスクトップのみ) */
  740. @media (min-width: 769px) {
  741.     .mycarousel-slide.side-slide {
  742.         opacity: 0.6;
  743.     }
  744.     .mycarousel-slide.side-slide .desktop-image {
  745.         filter: brightness(0.7) contrast(0.9);
  746.     }
  747.     .mycarousel-slide.center-slide {
  748.         opacity: 1;
  749.     }
  750.     .mycarousel-slide.center-slide .desktop-image {
  751.         filter: brightness(1) contrast(1);
  752.     }
  753.     .mycarousel-slide.side-slide:hover {
  754.         opacity: 0.8;
  755.         transform: scale(1.02);
  756.     }
  757.     .mycarousel-slide.side-slide:hover .desktop-image {
  758.         filter: brightness(0.85) contrast(0.95);
  759.     }
  760. }
  761. /* 動的高さ調整用のユーティリティクラス */
  762. .dynamic-fit-contain {
  763.     object-fit: contain;
  764. }
  765. .dynamic-fit-cover {
  766.     object-fit: cover;
  767. }
  768. </style>
  769. {% endblock %}
  770. {% block javascript %}
  771. <script>
  772. \$(function() {
  773.     // 動的レスポンシブ設定
  774.     const RESPONSIVE_CONFIG = {
  775.         desktop: {
  776.             targetAspectRatio: 16/9,
  777.             minHeight: '30vh',
  778.             maxHeight: '60vh',
  779.             marginThreshold: 0.15
  780.         },
  781.         mobile: {
  782.             targetAspectRatio: 4/3,
  783.             minHeight: '35vh',
  784.             maxHeight: '85vh',
  785.             marginThreshold: 0.12
  786.         }
  787.     };
  788.     let isInitialized = false;
  789.     let currentImages = [];
  790.     // 画面幅に応じた動的centerPadding計算
  791.     function calculateCenterPadding() {
  792.         const windowWidth = \$(window).width();
  793.         let padding;
  794.         
  795.         // 画面幅に応じてcenterPaddingを計算(調整可能な閾値)
  796.         if (windowWidth <= 768) {
  797.             // モバイル: 余白なし
  798.             padding = '0';
  799.         } else if (windowWidth <= 1024) {
  800.             // タブレット: 小さめの余白
  801.             padding = '8vw';
  802.         } else if (windowWidth <= 1200) {
  803.             // 小型デスクトップ: 中程度の余白
  804.             padding = '12vw';
  805.         }else if (windowWidth <= 1440) {
  806.             // 小型デスクトップ: 中程度の余白
  807.             padding = '15vw';
  808.         
  809.         } else if (windowWidth <= 1920) {
  810.             // 標準デスクトップ: やや大きめの余白
  811.             padding = '20vw';
  812.         } else {
  813.             // 大型ディスプレイ: 最大余白を制限
  814.             padding = '25vw';
  815.         }
  816.         
  817.         return padding;
  818.     }
  819.     // centerPaddingを動的に更新する関数
  820.     function updateCenterPadding() {
  821.         const newPadding = calculateCenterPadding();
  822.         const windowWidth = \$(window).width();
  823.         
  824.         // モバイルはcenterMode自体を無効にする
  825.         const centerModeEnabled = windowWidth > 768;
  826.         
  827.         if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
  828.             \$('.mycarousel-slider').slick('slickSetOption', 'centerMode', centerModeEnabled, false);
  829.             \$('.mycarousel-slider').slick('slickSetOption', 'centerPadding', newPadding, true);
  830.         }
  831.     }
  832.     // 現在のデバイスに応じた画像を取得
  833.     function getCurrentImages() {
  834.         const isMobile = \$(window).width() <= 768;
  835.         return isMobile ? \$('.mobile-image') : \$('.desktop-image');
  836.     }
  837.     // 画像プリロード関数
  838.     function preloadImages() {
  839.         return new Promise((resolve) => {
  840.             const images = getCurrentImages();
  841.             let loadedCount = 0;
  842.             const totalImages = images.length;
  843.             if (totalImages === 0) {
  844.                 resolve();
  845.                 return;
  846.             }
  847.             images.each(function() {
  848.                 const img = this;
  849.                 
  850.                 if (img.complete && img.naturalWidth > 0) {
  851.                     loadedCount++;
  852.                     if (loadedCount >= totalImages) {
  853.                         resolve();
  854.                     }
  855.                 } else {
  856.                     \$(img).on('load error', function() {
  857.                         loadedCount++;
  858.                         if (loadedCount >= totalImages) {
  859.                             resolve();
  860.                         }
  861.                     });
  862.                     
  863.                     // 強制的に再読み込みをトリガー(キャッシュ対策)
  864.                     if (!img.src) {
  865.                         img.src = img.getAttribute('src');
  866.                     }
  867.                 }
  868.             });
  869.         });
  870.     }
  871.     // スライダー初期化(動的centerPadding対応版)
  872.     function initializeSlider() {
  873.         if (\$('.mycarousel-slider').hasClass('slick-initialized')) {
  874.             \$('.mycarousel-slider').slick('unslick');
  875.         }
  876.         const initialPadding = calculateCenterPadding();
  877.         const windowWidth = \$(window).width();
  878.         const centerModeEnabled = windowWidth > 768;
  879.         \$('.mycarousel-slider').slick({
  880.             centerMode: centerModeEnabled,
  881.             centerPadding: initialPadding,
  882.             slidesToShow: 1,
  883.             autoplay: false, // 初期化時は自動再生を無効にして安定性を確保
  884.             autoplaySpeed: 5000,
  885.             arrows: true,
  886.             dots: true,
  887.             adaptiveHeight: false,
  888.             fade: false,
  889.             speed: 300
  890.             // responsive設定は削除(動的制御に切り替え)
  891.         });
  892.         // スライド変更時にクラスを更新
  893.         \$('.mycarousel-slider').on('afterChange', function(event, slick, currentSlide) {
  894.             updateSlideClasses();
  895.         });
  896.     }
  897.     // 動的な表示最適化メイン関数
  898.     function optimizeCarouselDisplay() {
  899.         const isMobile = \$(window).width() <= 768;
  900.         const config = isMobile ? RESPONSIVE_CONFIG.mobile : RESPONSIVE_CONFIG.desktop;
  901.         const \$currentImages = getCurrentImages();
  902.         
  903.         if (\$currentImages.length === 0) return;
  904.         // モバイル時は簡単な設定にする
  905.         if (isMobile) {
  906.             // モバイル時:width 100vw、height auto
  907.             \$('.mycarousel-slide').css({
  908.                 'height': 'auto',
  909.                 'width': '100vw'
  910.             });
  911.             \$currentImages.css({
  912.                 'width': '100%',
  913.                 'height': 'auto',
  914.                 'object-fit': 'contain',
  915.                 'position': 'relative'
  916.             });
  917.             
  918.             // 初期化完了後に自動再生を開始
  919.             if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
  920.                 \$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
  921.             }
  922.             return;
  923.         }
  924.         const \$firstImage = \$currentImages.filter(':visible').first();
  925.         if (\$firstImage.length === 0 || !\$firstImage[0].complete || !\$firstImage[0].naturalWidth) {
  926.             return;
  927.         }
  928.         const imageWidth = \$firstImage[0].naturalWidth;
  929.         const imageHeight = \$firstImage[0].naturalHeight;
  930.         const imageAspectRatio = imageWidth / imageHeight;
  931.         
  932.         const containerWidth = \$('.mycarousel-wrapper').width();
  933.         const containerAspectRatio = config.targetAspectRatio;
  934.         
  935.         const maxRenderWidth = Math.min(imageWidth, containerWidth);
  936.         const maxRenderHeight = maxRenderWidth / imageAspectRatio;
  937.         
  938.         const viewportMinHeightPx = parseFloat(config.minHeight) * \$(window).height() / 100;
  939.         const viewportMaxHeightPx = parseFloat(config.maxHeight) * \$(window).height() / 100;
  940.         
  941.         let optimalHeight;
  942.         let objectFitMode = 'contain';
  943.         const aspectRatioDiff = Math.abs(imageAspectRatio - containerAspectRatio) / containerAspectRatio;
  944.         if (maxRenderHeight <= viewportMaxHeightPx && maxRenderHeight >= viewportMinHeightPx) {
  945.             optimalHeight = maxRenderHeight;
  946.         } else if (maxRenderHeight > viewportMaxHeightPx) {
  947.             if (aspectRatioDiff <= config.marginThreshold) {
  948.                 optimalHeight = viewportMaxHeightPx;
  949.             } else {
  950.                 optimalHeight = Math.min(containerWidth / imageAspectRatio, viewportMaxHeightPx);
  951.             }
  952.         } else {
  953.             if (maxRenderHeight < viewportMinHeightPx) {
  954.                 const scaleUpLimit = Math.min(2.0, viewportMinHeightPx / maxRenderHeight);
  955.                 if (scaleUpLimit <= 1.5) {
  956.                     optimalHeight = viewportMinHeightPx;
  957.                 } else {
  958.                     optimalHeight = maxRenderHeight;
  959.                 }
  960.             } else {
  961.                 optimalHeight = maxRenderHeight;
  962.             }
  963.         }
  964.         // 最終的な制限適用
  965.         optimalHeight = Math.max(viewportMinHeightPx, Math.min(viewportMaxHeightPx, optimalHeight));
  966.         // 画像の品質を考慮したobject-fit調整
  967.         const renderScale = optimalHeight / maxRenderHeight;
  968.         if (renderScale > 1.2) {
  969.             objectFitMode = 'contain';
  970.         } else {
  971.             objectFitMode = 'contain';
  972.         }
  973.         // スタイル適用(デスクトップのみ)
  974.         \$('.mycarousel-slide').css('height', optimalHeight + 'px');
  975.         \$currentImages.css({
  976.             'object-fit': objectFitMode,
  977.             'image-rendering': renderScale > 1.1 ? 'smooth' : 'auto'
  978.         });
  979.         // 初期化完了後に自動再生を開始
  980.         if (isInitialized && \$('.mycarousel-slider').slick('slickGetOption', 'autoplay') === false) {
  981.             \$('.mycarousel-slider').slick('slickSetOption', 'autoplay', true, true);
  982.         }
  983.     }
  984.     // スライドのクラスを更新する関数
  985.     function updateSlideClasses() {
  986.         \$('.mycarousel-slide').removeClass('center-slide side-slide');
  987.         
  988.         if (\$(window).width() > 768) {
  989.             \$('.slick-center .mycarousel-slide').addClass('center-slide');
  990.             \$('.slick-slide:not(.slick-center) .mycarousel-slide').addClass('side-slide');
  991.         } else {
  992.             \$('.mycarousel-slide').addClass('center-slide');
  993.         }
  994.     }
  995.     async function initialize() {
  996.         try {
  997.             // カルーセルを一時的に非表示にしてちらつき防止
  998.             \$('.mycarousel-wrapper').css('visibility', 'hidden');
  999.             
  1000.             await preloadImages();
  1001.             
  1002.             initializeSlider();
  1003.             
  1004.             optimizeCarouselDisplay();
  1005.             
  1006.             updateSlideClasses();
  1007.             
  1008.             isInitialized = true;
  1009.             
  1010.             // 6. 少し待ってから表示(slickの初期化完了を確実にする)
  1011.             setTimeout(() => {
  1012.                 \$('.mycarousel-wrapper').css('visibility', 'visible');
  1013.                 // 初期化後にもう一度表示を最適化
  1014.                 optimizeCarouselDisplay();
  1015.                 updateSlideClasses();
  1016.             }, 50);
  1017.             
  1018.             console.log('Carousel initialized successfully');
  1019.             
  1020.         } catch (error) {
  1021.             console.error('Carousel initialization failed:', error);
  1022.             // エラー時も表示を戻す
  1023.             \$('.mycarousel-wrapper').css('visibility', 'visible');
  1024.         }
  1025.     }
  1026.     let resizeTimer;
  1027.     \$(window).on('resize', function() {
  1028.         clearTimeout(resizeTimer);
  1029.         resizeTimer = setTimeout(async () => {
  1030.             // centerPaddingを動的に更新
  1031.             updateCenterPadding();
  1032.             
  1033.             // デバイス切り替わり時は再初期化
  1034.             const newImages = getCurrentImages();
  1035.             const imagesSwitched = !currentImages.length || 
  1036.                 newImages.length !== currentImages.length ||
  1037.                 newImages[0] !== currentImages[0];
  1038.             
  1039.             if (imagesSwitched) {
  1040.                 currentImages = newImages;
  1041.                 await preloadImages();
  1042.             }
  1043.             
  1044.             optimizeCarouselDisplay();
  1045.             updateSlideClasses();
  1046.         }, 200);
  1047.     });
  1048.     
  1049.     \$(document).ready(function() {
  1050.         currentImages = getCurrentImages();
  1051.         initialize();
  1052.     });
  1053.     
  1054.     \$(window).on('load', function() {
  1055.         if (!isInitialized) {
  1056.             initialize();
  1057.         }
  1058.     });
  1059. });
  1060. </script>
  1061. {% endblock %}""index.twig""/home/iseyabread/www/iseya/app/template/default/index.twig");
  1062.     }
  1063. }