vendor/uvdesk/support-center-bundle/Resources/views/Knowledgebase/modern-unified.html.twig line 1

Open in your IDE?
  1. {% extends "@UVDeskSupportCenter/Templates/layout.html.twig" %}
  2. {% block title %}Base de Conocimientos{% endblock %}
  3. {% block body %}
  4. <div class="modern-kb-container" id="modern-kb-container">
  5.     <div class="modern-kb-wrapper">
  6.         <!-- Sidebar Navigation -->
  7.         <aside class="modern-kb-sidebar">
  8.             <div class="modern-kb-sidebar-header">
  9.                 <h2>{{ 'Base de Conocimientos'|trans }}</h2>
  10.                 <a href="{{ path('helpdesk_knowledgebase') }}" class="kb-back-to-topics" title="{{ 'Volver a temas frecuentes'|trans }}">
  11.                     ← {{ 'Temas frecuentes'|trans }}
  12.                 </a>
  13.                 <div class="kb-search-container">
  14.                     <input type="text" 
  15.                            id="kb-search-input" 
  16.                            class="kb-search-input" 
  17.                            placeholder="{{ 'Buscar artículos...'|trans }}"
  18.                            autocomplete="off">
  19.                     <span class="kb-search-icon">🔍</span>
  20.                     <button type="button" class="kb-search-clear" id="kb-search-clear" style="display: none;">✕</button>
  21.                 </div>
  22.                 <div class="kb-search-results-count" id="kb-search-results-count" style="display: none;">
  23.                     <span id="kb-results-number">0</span> {{ 'resultados encontrados'|trans }}
  24.                 </div>
  25.             </div>
  26.             
  27.             <nav class="modern-kb-nav" id="kb-navigation">
  28.                 {% if structure|length == 0 %}
  29.                     <div style="padding: 20px; color: #bdc3c7; text-align: center;">
  30.                         <p>No hay carpetas disponibles</p>
  31.                     </div>
  32.                 {% else %}
  33.                     {% for folder in structure %}
  34.                     <div class="modern-kb-folder-section">
  35.                         <div class="modern-kb-folder-header" data-folder-id="{{ folder.id }}">
  36.                             {% if folder.solutionImage %}
  37.                                 <img src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}{{ folder.solutionImage }}" 
  38.                                      class="folder-icon" alt="{{ folder.name }}">
  39.                             {% else %}
  40.                                 <span class="folder-icon-placeholder">{{ folder.name|slice(0, 2)|upper }}</span>
  41.                             {% endif %}
  42.                             <span class="folder-name">{{ folder.name }}</span>
  43.                             <span class="folder-toggle">▼</span>
  44.                         </div>
  45.                         
  46.                         <div class="modern-kb-folder-content" id="folder-{{ folder.id }}" style="max-height: 0px; opacity: 0; overflow: hidden; padding-top: 0; padding-bottom: 0;">
  47.                             {% if folder.categories|length > 0 %}
  48.                                 {% for category in folder.categories %}
  49.                                     <div class="modern-kb-category-section">
  50.                                         <div class="modern-kb-category-header" data-category-id="{{ category.id }}">
  51.                                             <span class="category-name">{{ category.name }}</span>
  52.                                             <span class="category-count">({{ category.articleCount }})</span>
  53.                                             <span class="category-toggle">▶</span>
  54.                                         </div>
  55.                                         
  56.                                         <ul class="modern-kb-articles-list" id="category-{{ category.id }}" style="display: none;">
  57.                                             {% for article in category.articles %}
  58.                                                 {% set articleId = article.id is defined ? article.id : (article.getId is defined ? article.getId() : null) %}
  59.                                                 {% set articleName = article.name is defined ? article.name : (article.getName is defined ? article.getName() : 'Sin título') %}
  60.                                                 {% set articleSlug = article.slug is defined ? article.slug : (article.getSlug is defined ? article.getSlug() : '') %}
  61.                                                 {% set articleStared = article.stared is defined ? article.stared : (article.getStared is defined ? article.getStared() : false) %}
  62.                                                 <li class="modern-kb-article-item">
  63.                                                     <a href="#" 
  64.                                                        class="kb-article-link" 
  65.                                                        data-article-slug="{{ articleSlug }}"
  66.                                                        data-article-id="{{ articleId }}">
  67.                                                         {% if articleStared %}<span class="article-star">⭐</span>{% endif %}
  68.                                                         {{ articleName }}
  69.                                                     </a>
  70.                                                 </li>
  71.                                             {% endfor %}
  72.                                         </ul>
  73.                                     </div>
  74.                                 {% endfor %}
  75.                             {% endif %}
  76.                             
  77.                             {% if folder.directArticles|length > 0 %}
  78.                                 <div class="modern-kb-direct-articles">
  79.                                     <div class="modern-kb-category-header" data-category-id="direct-{{ folder.id }}" style="cursor: pointer;">
  80.                                         <span class="category-name">{{ 'Artículos Directos'|trans }}</span>
  81.                                         <span class="category-count">({{ folder.directArticles|length }})</span>
  82.                                         <span class="category-toggle">▶</span>
  83.                                     </div>
  84.                                     <ul class="modern-kb-articles-list" id="category-direct-{{ folder.id }}" style="display: none;">
  85.                                         {% for article in folder.directArticles %}
  86.                                             {% set articleId = article.id is defined ? article.id : (article.getId is defined ? article.getId() : null) %}
  87.                                             {% set articleName = article.name is defined ? article.name : (article.getName is defined ? article.getName() : 'Sin título') %}
  88.                                             {% set articleSlug = article.slug is defined ? article.slug : (article.getSlug is defined ? article.getSlug() : '') %}
  89.                                             {% set articleStared = article.stared is defined ? article.stared : (article.getStared is defined ? article.getStared() : false) %}
  90.                                             <li class="modern-kb-article-item">
  91.                                                 <a href="#" 
  92.                                                    class="kb-article-link" 
  93.                                                    data-article-slug="{{ articleSlug }}"
  94.                                                    data-article-id="{{ articleId }}">
  95.                                                     {% if articleStared %}<span class="article-star">⭐</span>{% endif %}
  96.                                                     {{ articleName }}
  97.                                                 </a>
  98.                                             </li>
  99.                                         {% endfor %}
  100.                                     </ul>
  101.                                 </div>
  102.                             {% endif %}
  103.                         </div>
  104.                     </div>
  105.                     {% endfor %}
  106.                 {% endif %}
  107.             </nav>
  108.         </aside>
  109.         
  110.         <!-- Main Content Area -->
  111.         <main class="modern-kb-content">
  112.             <!-- Content Search Bar -->
  113.             <div class="kb-content-search-bar">
  114.                 <div class="kb-content-search-container">
  115.                     <input type="text" 
  116.                            id="kb-content-search-input" 
  117.                            class="kb-content-search-input" 
  118.                            placeholder="{{ 'Buscar en el contenido de los artículos...'|trans }}"
  119.                            autocomplete="off">
  120.                     <span class="kb-content-search-icon">🔍</span>
  121.                     <button type="button" class="kb-content-search-clear" id="kb-content-search-clear" style="display: none;">✕</button>
  122.                 </div>
  123.                 <div class="kb-content-search-results-count" id="kb-content-search-results-count" style="display: none;">
  124.                     <span id="kb-content-results-number">0</span> {{ 'artículos encontrados'|trans }}
  125.                 </div>
  126.             </div>
  127.             
  128.             <div id="kb-article-viewer">
  129.                 <!-- Welcome Screen -->
  130.                 <div class="kb-welcome-screen" id="welcome-screen">
  131.                     <div class="kb-welcome-content">
  132.                         <h1>{{ 'Bienvenido a la Base de Conocimientos'|trans }}</h1>
  133.                         <p>{{ 'Seleccione un artículo del menú lateral para comenzar o navegue por todo el contenido'|trans }}</p>
  134.                         <div class="kb-stats">
  135.                             {% set totalArticles = 0 %}
  136.                             {% for folder in structure %}
  137.                                 {% set totalArticles = totalArticles + folder.totalArticles %}
  138.                             {% endfor %}
  139.                             <div class="kb-stat-item">
  140.                                 <span class="kb-stat-number">{{ structure|length }}</span>
  141.                                 <span class="kb-stat-label">{{ 'Carpetas'|trans }}</span>
  142.                             </div>
  143.                             <div class="kb-stat-item">
  144.                                 <span class="kb-stat-number">{{ totalArticles }}</span>
  145.                                 <span class="kb-stat-label">{{ 'Artículos'|trans }}</span>
  146.                             </div>
  147.                         </div>
  148.                     </div>
  149.                 </div>
  150.                 
  151.                 <!-- All Articles Content -->
  152.                 <div class="kb-all-articles-content">
  153.                     {% for folder in structure %}
  154.                         <div class="kb-folder-content-section" data-folder-id="{{ folder.id }}">
  155.                             <div class="kb-folder-title-section">
  156.                                 <h2 class="kb-folder-title">{{ folder.name }}</h2>
  157.                                 {% if folder.description %}
  158.                                     <p class="kb-folder-description">{{ folder.description }}</p>
  159.                                 {% endif %}
  160.                             </div>
  161.                             
  162.                             {% if folder.categories|length > 0 %}
  163.                                 {% for category in folder.categories %}
  164.                                     <div class="kb-category-content-section" data-category-id="{{ category.id }}">
  165.                                         <h3 class="kb-category-title">{{ category.name }}</h3>
  166.                                         {% if category.description %}
  167.                                             <p class="kb-category-description">{{ category.description }}</p>
  168.                                         {% endif %}
  169.                                         
  170.                                         <div class="kb-category-articles">
  171.                                             {% for article in category.articles %}
  172.                                                 {% set articleId = article.id is defined ? article.id : (article.getId is defined ? article.getId() : null) %}
  173.                                                 {% set articleName = article.name is defined ? article.name : (article.getName is defined ? article.getName() : 'Sin título') %}
  174.                                                 {% set articleSlug = article.slug is defined ? article.slug : (article.getSlug is defined ? article.getSlug() : '') %}
  175.                                                 {% set articleContent = article.content is defined ? article.content : (article.getContent is defined ? article.getContent() : '') %}
  176.                                                 {% set articleDateAdded = article.dateAdded is defined ? article.dateAdded : (article.getDateAdded is defined ? article.getDateAdded() : null) %}
  177.                                                 
  178.                                                 <article class="kb-article-display" id="article-{{ articleSlug }}" data-article-slug="{{ articleSlug }}" data-article-id="{{ articleId }}">
  179.                                                     <header class="kb-article-header">
  180.                                                         <h1>{{ articleName }}</h1>
  181.                                                         {% if articleDateAdded %}
  182.                                                             <div class="kb-article-meta">
  183.                                                                 <span class="kb-article-date">
  184.                                                                     {{ 'Publicado el'|trans }} {{ articleDateAdded }}
  185.                                                                 </span>
  186.                                                             </div>
  187.                                                         {% endif %}
  188.                                                     </header>
  189.                                                     <div class="kb-article-body">
  190.                                                         {{ articleContent|raw }}
  191.                                                     </div>
  192.                                                     {% if article.subarticles is defined and article.subarticles is not empty %}
  193.                                                         <hr>
  194.                                                         <h2>{{ 'Related sections'|trans }}</h2>
  195.                                                         <div class="uv-subarticles-list">
  196.                                                             {% for sub in article.subarticles %}
  197.                                                                 <article class="uv-subarticle">
  198.                                                                     <h3>{{ sub.name }}</h3>
  199.                                                                     <div class="uv-subarticle-content">{{ sub.content|raw }}</div>
  200.                                                                 </article>
  201.                                                             {% endfor %}
  202.                                                         </div>
  203.                                                     {% endif %}
  204.                                                 </article>
  205.                                             {% endfor %}
  206.                                         </div>
  207.                                     </div>
  208.                                 {% endfor %}
  209.                             {% endif %}
  210.                             
  211.                             {% if folder.directArticles|length > 0 %}
  212.                                 <div class="kb-direct-articles-section" data-folder-id="{{ folder.id }}">
  213.                                     <h3 class="kb-category-title">{{ 'Artículos Directos'|trans }}</h3>
  214.                                     <div class="kb-category-articles">
  215.                                         {% for article in folder.directArticles %}
  216.                                             {% set articleId = article.id is defined ? article.id : (article.getId is defined ? article.getId() : null) %}
  217.                                             {% set articleName = article.name is defined ? article.name : (article.getName is defined ? article.getName() : 'Sin título') %}
  218.                                             {% set articleSlug = article.slug is defined ? article.slug : (article.getSlug is defined ? article.getSlug() : '') %}
  219.                                             {% set articleContent = article.content is defined ? article.content : (article.getContent is defined ? article.getContent() : '') %}
  220.                                             {% set articleDateAdded = article.dateAdded is defined ? article.dateAdded : (article.getDateAdded is defined ? article.getDateAdded() : null) %}
  221.                                             
  222.                                             <article class="kb-article-display" id="article-{{ articleSlug }}" data-article-slug="{{ articleSlug }}" data-article-id="{{ articleId }}">
  223.                                                 <header class="kb-article-header">
  224.                                                     <h1>{{ articleName }}</h1>
  225.                                                     {% if articleDateAdded %}
  226.                                                         <div class="kb-article-meta">
  227.                                                             <span class="kb-article-date">
  228.                                                                 {{ 'Publicado el'|trans }} {{ articleDateAdded }}
  229.                                                             </span>
  230.                                                         </div>
  231.                                                     {% endif %}
  232.                                                 </header>
  233.                                                 <div class="kb-article-body">
  234.                                                     {{ articleContent|raw }}
  235.                                                 </div>
  236.                                                 {% if article.subarticles is defined and article.subarticles is not empty %}
  237.                                                         <hr>
  238.                                                         <h2>{{ 'Related sections'|trans }}</h2>
  239.                                                         <div class="uv-subarticles-list">
  240.                                                             {% for sub in article.subarticles %}
  241.                                                                 <article class="uv-subarticle">
  242.                                                                     <h3>{{ sub.name }}</h3>
  243.                                                                     <div class="uv-subarticle-content">{{ sub.content|raw }}</div>
  244.                                                                 </article>
  245.                                                             {% endfor %}
  246.                                                         </div>
  247.                                                 {% endif %}
  248.                                             </article>
  249.                                         {% endfor %}
  250.                                     </div>
  251.                                 </div>
  252.                             {% endif %}
  253.                         </div>
  254.                     {% endfor %}
  255.                 </div>
  256.             </div>
  257.         </main>
  258.     </div>
  259. </div>
  260. <style>
  261. .modern-kb-container {
  262.     width: 100%;
  263.     min-height: calc(100vh - 200px);
  264.     background: #f8f9fa;
  265.     padding: 20px 0;
  266. }
  267. .modern-kb-wrapper {
  268.     display: flex;
  269.     max-width: 1400px;
  270.     margin: 0 auto;
  271.     background: #fff;
  272.     border-radius: 8px;
  273.     box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  274.     overflow: hidden;
  275.     height: calc(100vh - 250px);
  276.     min-height: calc(100vh - 250px);
  277.     max-height: calc(100vh - 250px);
  278. }
  279. /* Sidebar Styles */
  280. .modern-kb-sidebar {
  281.     width: 320px;
  282.     background: #2c3e50;
  283.     color: #ecf0f1;
  284.     overflow: hidden;
  285.     flex-shrink: 0;
  286.     height: 100%;
  287.     display: flex;
  288.     flex-direction: column;
  289. }
  290. /* Sidebar scrollbar */
  291. .modern-kb-sidebar::-webkit-scrollbar,
  292. .modern-kb-nav::-webkit-scrollbar {
  293.     width: 8px;
  294. }
  295. .modern-kb-sidebar::-webkit-scrollbar-track,
  296. .modern-kb-nav::-webkit-scrollbar-track {
  297.     background: #1a252f;
  298. }
  299. .modern-kb-sidebar::-webkit-scrollbar-thumb,
  300. .modern-kb-nav::-webkit-scrollbar-thumb {
  301.     background: #34495e;
  302.     border-radius: 4px;
  303. }
  304. .modern-kb-sidebar::-webkit-scrollbar-thumb:hover,
  305. .modern-kb-nav::-webkit-scrollbar-thumb:hover {
  306.     background: #4a5f7a;
  307. }
  308. .modern-kb-sidebar-header {
  309.     padding: 20px;
  310.     background: #34495e;
  311.     border-bottom: 2px solid #1a252f;
  312.     flex-shrink: 0;
  313. }
  314. .modern-kb-sidebar-header h2 {
  315.     margin: 0 0 15px 0;
  316.     font-size: 18px;
  317.     font-weight: 600;
  318.     color: #ecf0f1;
  319. }
  320. .kb-back-to-topics {
  321.     display: inline-block;
  322.     margin-top: 10px;
  323.     padding: 8px 12px;
  324.     background: rgba(52, 152, 219, 0.2);
  325.     color: #3498db;
  326.     text-decoration: none;
  327.     border-radius: 4px;
  328.     font-size: 13px;
  329.     transition: background 0.2s, color 0.2s;
  330. }
  331. .kb-back-to-topics:hover {
  332.     background: rgba(52, 152, 219, 0.3);
  333.     color: #5dade2;
  334. }
  335. /* Search Styles */
  336. .kb-search-container {
  337.     position: relative;
  338.     margin-bottom: 10px;
  339. }
  340. .kb-search-input {
  341.     width: 100%;
  342.     padding: 10px 35px 10px 35px;
  343.     background: #1a252f;
  344.     border: 1px solid #34495e;
  345.     border-radius: 4px;
  346.     color: #ecf0f1;
  347.     font-size: 14px;
  348.     box-sizing: border-box;
  349.     transition: border-color 0.2s, background 0.2s;
  350. }
  351. .kb-search-input:not(:placeholder-shown) {
  352.     padding-right: 50px; /* More space when clear button is visible */
  353. }
  354. .kb-search-input:focus {
  355.     outline: none;
  356.     border-color: #3498db;
  357.     background: #2c3e50;
  358. }
  359. .kb-search-input::placeholder {
  360.     color: #7f8c8d;
  361. }
  362. .kb-search-icon {
  363.     position: absolute;
  364.     left: 12px;
  365.     top: 50%;
  366.     transform: translateY(-50%);
  367.     color: #7f8c8d;
  368.     pointer-events: none;
  369.     font-size: 14px;
  370. }
  371. .kb-search-clear {
  372.     position: absolute;
  373.     right: 8px;
  374.     top: 50%;
  375.     transform: translateY(-50%);
  376.     background: transparent;
  377.     border: none;
  378.     color: #7f8c8d;
  379.     cursor: pointer;
  380.     font-size: 16px;
  381.     padding: 4px 8px;
  382.     border-radius: 3px;
  383.     transition: color 0.2s, background 0.2s;
  384. }
  385. .kb-search-clear:hover {
  386.     color: #ecf0f1;
  387.     background: #34495e;
  388. }
  389. .kb-search-results-count {
  390.     margin-top: 8px;
  391.     font-size: 12px;
  392.     color: #95a5a6;
  393.     text-align: center;
  394. }
  395. .kb-search-results-count span {
  396.     font-weight: 600;
  397.     color: #3498db;
  398. }
  399. /* Highlight styles for search matches */
  400. .kb-search-highlight {
  401.     background: rgba(52, 152, 219, 0.3);
  402.     padding: 2px 4px;
  403.     border-radius: 2px;
  404. }
  405. /* Styles for filtered/hidden items */
  406. .modern-kb-folder-section.hidden-by-search,
  407. .modern-kb-category-section.hidden-by-search,
  408. .modern-kb-article-item.hidden-by-search,
  409. .kb-article-display.hidden-by-content-search,
  410. .kb-folder-content-section.hidden-by-content-search,
  411. .kb-category-content-section.hidden-by-content-search {
  412.     display: none !important;
  413. }
  414. .modern-kb-folder-section.visible-by-search,
  415. .modern-kb-category-section.visible-by-search {
  416.     display: block !important;
  417. }
  418. /* Welcome screen visibility */
  419. .kb-welcome-screen.hidden-by-content-search {
  420.     display: none !important;
  421. }
  422. /* Content search highlight */
  423. .kb-content-search-highlight,
  424. mark.kb-content-search-highlight {
  425.     background: rgba(255, 235, 59, 0.5);
  426.     padding: 2px 4px;
  427.     border-radius: 3px;
  428.     font-weight: 500;
  429.     color: #2c3e50;
  430. }
  431. .modern-kb-nav {
  432.     padding: 10px 0;
  433.     flex: 1;
  434.     overflow-y: auto;
  435.     overflow-x: hidden;
  436.     position: relative;
  437.     width: 100%;
  438. }
  439. .modern-kb-folder-section {
  440.     border-bottom: 1px solid #34495e;
  441.     position: relative;
  442.     width: 100%;
  443.     display: block;
  444.     margin: 0;
  445.     padding: 0;
  446. }
  447. .modern-kb-folder-header {
  448.     padding: 12px 20px;
  449.     cursor: pointer;
  450.     display: flex;
  451.     align-items: center;
  452.     gap: 12px;
  453.     transition: background 0.2s;
  454.     user-select: none;
  455.     color: #ecf0f1 !important;
  456.     visibility: visible !important;
  457.     opacity: 1 !important;
  458.     position: relative;
  459.     width: 100%;
  460.     box-sizing: border-box;
  461.     min-height: 48px;
  462.     z-index: 1;
  463. }
  464. .modern-kb-folder-header:hover {
  465.     background: #34495e;
  466. }
  467. .modern-kb-folder-header.active {
  468.     background: #3498db;
  469. }
  470. .folder-icon,
  471. .folder-icon-placeholder {
  472.     width: 32px;
  473.     height: 32px;
  474.     border-radius: 4px;
  475.     flex-shrink: 0;
  476. }
  477. .folder-icon {
  478.     object-fit: cover;
  479. }
  480. .folder-icon-placeholder {
  481.     background: #3498db;
  482.     display: flex;
  483.     align-items: center;
  484.     justify-content: center;
  485.     font-size: 12px;
  486.     font-weight: bold;
  487.     color: #fff !important;
  488.     visibility: visible !important;
  489. }
  490. .folder-name {
  491.     flex: 1;
  492.     min-width: 0;
  493.     font-weight: 500;
  494.     color: #ecf0f1 !important;
  495.     visibility: visible !important;
  496.     opacity: 1 !important;
  497.     font-size: 14px;
  498.     line-height: 1.4;
  499.     overflow: hidden;
  500.     text-overflow: ellipsis;
  501.     white-space: nowrap;
  502. }
  503. .folder-toggle {
  504.     font-size: 10px;
  505.     transition: transform 0.2s;
  506.     color: #ecf0f1 !important;
  507.     visibility: visible !important;
  508.     opacity: 1 !important;
  509.     flex-shrink: 0;
  510.     width: 16px;
  511.     text-align: center;
  512.     margin-left: 4px;
  513. }
  514. .modern-kb-folder-header.active .folder-toggle {
  515.     transform: rotate(180deg);
  516. }
  517. .modern-kb-folder-content {
  518.     background: #1a252f;
  519.     overflow: hidden;
  520.     transition: max-height 0.3s ease-out, opacity 0.3s ease-out, padding 0.3s ease-out;
  521.     color: #bdc3c7;
  522.     position: relative;
  523.     width: 100%;
  524.     display: block;
  525.     box-sizing: border-box;
  526.     margin: 0;
  527.     padding: 0;
  528.     will-change: max-height;
  529.     clear: both;
  530. }
  531. .modern-kb-folder-content.expanded {
  532.     color: #bdc3c7 !important;
  533. }
  534. .modern-kb-folder-content * {
  535.     visibility: visible !important;
  536.     color: #bdc3c7 !important;
  537.     text-shadow: none !important;
  538.     position: relative !important;
  539. }
  540. .modern-kb-folder-content.expanded * {
  541.     color: #bdc3c7 !important;
  542.     visibility: visible !important;
  543.     opacity: 1 !important;
  544. }
  545. .modern-kb-folder-content span {
  546.     color: #bdc3c7 !important;
  547.     opacity: 1 !important;
  548.     visibility: visible !important;
  549. }
  550. /* Asegurar que no haya elementos superpuestos */
  551. .modern-kb-folder-content > * {
  552.     position: relative !important;
  553.     float: none !important;
  554.     clear: both !important;
  555. }
  556. .modern-kb-category-section {
  557.     border-bottom: 1px solid #2c3e50;
  558.     position: relative;
  559.     width: 100%;
  560.     display: block;
  561.     margin: 0;
  562.     padding: 0;
  563. }
  564. .modern-kb-category-header {
  565.     padding: 10px 20px 10px 50px;
  566.     cursor: pointer;
  567.     display: flex !important;
  568.     align-items: center;
  569.     gap: 8px;
  570.     transition: background 0.2s;
  571.     user-select: none;
  572.     font-size: 14px !important;
  573.     color: #bdc3c7 !important;
  574.     visibility: visible !important;
  575.     opacity: 1 !important;
  576.     position: relative !important;
  577.     z-index: 1 !important;
  578.     width: 100%;
  579.     box-sizing: border-box;
  580.     margin: 0;
  581.     clear: both;
  582.     min-height: 40px;
  583. }
  584. .modern-kb-category-header .category-name,
  585. .modern-kb-category-header .category-count,
  586. .modern-kb-category-header .category-toggle {
  587.     color: #bdc3c7 !important;
  588.     visibility: visible !important;
  589.     opacity: 1 !important;
  590.     display: inline-block !important;
  591.     font-size: 14px !important;
  592.     position: relative;
  593.     z-index: 2;
  594. }
  595. .modern-kb-category-header:hover {
  596.     background: #2c3e50;
  597. }
  598. .category-name {
  599.     flex: 1;
  600.     min-width: 0;
  601.     color: #bdc3c7 !important;
  602.     font-size: 14px !important;
  603.     visibility: visible !important;
  604.     overflow: hidden;
  605.     text-overflow: ellipsis;
  606.     white-space: nowrap;
  607.     position: relative;
  608.     z-index: 1;
  609.     display: block;
  610.     max-width: calc(100% - 80px);
  611. }
  612. .category-count {
  613.     font-size: 12px !important;
  614.     color: #95a5a6 !important;
  615.     visibility: visible !important;
  616.     flex-shrink: 0;
  617.     margin-left: 4px;
  618. }
  619. .category-toggle {
  620.     font-size: 10px !important;
  621.     transition: transform 0.2s;
  622.     color: #bdc3c7 !important;
  623.     visibility: visible !important;
  624.     flex-shrink: 0;
  625.     width: 12px;
  626.     text-align: center;
  627.     margin-left: 4px;
  628. }
  629. .modern-kb-category-header.active .category-toggle {
  630.     transform: rotate(90deg);
  631. }
  632. .modern-kb-articles-list {
  633.     list-style: none;
  634.     padding: 0;
  635.     margin: 0;
  636.     background: #1a252f;
  637.     visibility: visible !important;
  638.     opacity: 1 !important;
  639.     display: block !important;
  640.     position: relative;
  641.     width: 100%;
  642.     box-sizing: border-box;
  643.     clear: both;
  644.     min-height: 0;
  645. }
  646. .modern-kb-articles-list[style*="display: none"] {
  647.     display: none !important;
  648. }
  649. .modern-kb-article-item {
  650.     border-bottom: 1px solid #2c3e50;
  651.     position: relative;
  652.     width: 100%;
  653.     display: block;
  654.     margin: 0;
  655.     padding: 0;
  656. }
  657. .modern-kb-article-item:last-child {
  658.     border-bottom: none;
  659. }
  660. .kb-article-link {
  661.     display: block !important;
  662.     padding: 10px 20px 10px 70px;
  663.     color: #bdc3c7 !important;
  664.     text-decoration: none;
  665.     transition: all 0.2s;
  666.     font-size: 13px;
  667.     line-height: 1.5;
  668.     visibility: visible !important;
  669.     opacity: 1 !important;
  670.     cursor: pointer;
  671.     width: 100%;
  672.     box-sizing: border-box;
  673.     position: relative;
  674.     white-space: nowrap;
  675.     overflow: hidden;
  676.     text-overflow: ellipsis;
  677.     clear: both;
  678.     z-index: 1;
  679. }
  680. .kb-article-link:hover {
  681.     background: #2c3e50;
  682.     color: #3498db;
  683.     padding-left: 75px;
  684.     white-space: normal;
  685.     overflow: visible;
  686.     text-overflow: clip;
  687. }
  688. .kb-article-link.active {
  689.     background: #3498db;
  690.     color: #fff;
  691.     font-weight: 500;
  692. }
  693. .article-star {
  694.     margin-right: 6px;
  695.     font-size: 12px;
  696. }
  697. .modern-kb-direct-articles {
  698.     padding: 10px 0;
  699. }
  700. .modern-kb-direct-articles .modern-kb-category-header {
  701.     padding-left: 50px;
  702.     cursor: pointer;
  703. }
  704. .modern-kb-direct-articles .modern-kb-category-header:hover {
  705.     background: #2c3e50;
  706. }
  707. /* Main Content Styles */
  708. .modern-kb-content {
  709.     flex: 1;
  710.     padding: 0;
  711.     background: #fff;
  712.     overflow-y: scroll;
  713.     overflow-x: hidden;
  714.     height: 100%;
  715.     position: relative;
  716.     display: flex;
  717.     flex-direction: column;
  718. }
  719. /* Force scrollbar to be visible always */
  720. .modern-kb-content {
  721.     overflow-y: scroll !important;
  722. }
  723. .modern-kb-content::-webkit-scrollbar {
  724.     width: 12px;
  725. }
  726. .modern-kb-content::-webkit-scrollbar-track {
  727.     background: #f1f1f1;
  728.     border-left: 1px solid #e0e0e0;
  729. }
  730. .modern-kb-content::-webkit-scrollbar-thumb {
  731.     background: #888;
  732.     border-radius: 6px;
  733.     border: 2px solid #f1f1f1;
  734. }
  735. .modern-kb-content::-webkit-scrollbar-thumb:hover {
  736.     background: #555;
  737. }
  738. /* Firefox scrollbar */
  739. .modern-kb-content {
  740.     scrollbar-width: thin;
  741.     scrollbar-color: #888 #f1f1f1;
  742. }
  743. /* Content Search Bar Styles */
  744. .kb-content-search-bar {
  745.     padding: 20px;
  746.     background: #f8f9fa;
  747.     border-bottom: 2px solid #e0e0e0;
  748.     flex-shrink: 0;
  749.     position: sticky;
  750.     top: 0;
  751.     z-index: 10;
  752.     box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  753. }
  754. .kb-content-search-container {
  755.     position: relative;
  756.     max-width: 800px;
  757.     margin: 0 auto;
  758. }
  759. .kb-content-search-input {
  760.     width: 100%;
  761.     padding: 12px 45px 12px 45px;
  762.     background: #fff;
  763.     border: 2px solid #ddd;
  764.     border-radius: 6px;
  765.     color: #2c3e50;
  766.     font-size: 16px;
  767.     box-sizing: border-box;
  768.     transition: border-color 0.2s, box-shadow 0.2s;
  769. }
  770. .kb-content-search-input:focus {
  771.     outline: none;
  772.     border-color: #3498db;
  773.     box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
  774. }
  775. .kb-content-search-input::placeholder {
  776.     color: #95a5a6;
  777. }
  778. .kb-content-search-input:not(:placeholder-shown) {
  779.     padding-right: 60px;
  780. }
  781. .kb-content-search-icon {
  782.     position: absolute;
  783.     left: 15px;
  784.     top: 50%;
  785.     transform: translateY(-50%);
  786.     color: #7f8c8d;
  787.     pointer-events: none;
  788.     font-size: 16px;
  789. }
  790. .kb-content-search-clear {
  791.     position: absolute;
  792.     right: 10px;
  793.     top: 50%;
  794.     transform: translateY(-50%);
  795.     background: transparent;
  796.     border: none;
  797.     color: #7f8c8d;
  798.     cursor: pointer;
  799.     font-size: 18px;
  800.     padding: 5px 10px;
  801.     border-radius: 4px;
  802.     transition: color 0.2s, background 0.2s;
  803. }
  804. .kb-content-search-clear:hover {
  805.     color: #2c3e50;
  806.     background: #ecf0f1;
  807. }
  808. .kb-content-search-results-count {
  809.     margin-top: 10px;
  810.     font-size: 14px;
  811.     color: #7f8c8d;
  812.     text-align: center;
  813. }
  814. .kb-content-search-results-count span {
  815.     font-weight: 600;
  816.     color: #3498db;
  817. }
  818. #kb-article-viewer {
  819.     padding: 0;
  820.     min-height: 100%;
  821.     background: #fff;
  822.     width: 100%;
  823.     overflow: visible;
  824.     flex: 1;
  825. }
  826. /* Asegurar que el contenido tenga altura suficiente para scroll */
  827. .kb-welcome-screen,
  828. .kb-article-display {
  829.     min-height: calc(100vh - 250px);
  830.     padding-bottom: 60px;
  831. }
  832. /* Estilos para el contenido completo de artículos */
  833. .kb-all-articles-content {
  834.     padding: 20px 0;
  835. }
  836. .kb-folder-content-section {
  837.     margin-bottom: 60px;
  838.     padding-bottom: 40px;
  839.     border-bottom: 2px solid #ecf0f1;
  840. }
  841. .kb-folder-content-section:last-child {
  842.     border-bottom: none;
  843. }
  844. .kb-folder-title-section {
  845.     margin-bottom: 30px;
  846.     padding-bottom: 20px;
  847.     border-bottom: 1px solid #ecf0f1;
  848. }
  849. .kb-folder-title {
  850.     font-size: 32px;
  851.     color: #2c3e50;
  852.     margin: 0 0 10px 0;
  853.     font-weight: 600;
  854. }
  855. .kb-folder-description {
  856.     font-size: 16px;
  857.     color: #7f8c8d;
  858.     margin: 0;
  859. }
  860. .kb-category-content-section {
  861.     margin-bottom: 40px;
  862. }
  863. .kb-category-title {
  864.     font-size: 24px;
  865.     color: #34495e;
  866.     margin: 30px 0 15px 0;
  867.     font-weight: 600;
  868.     padding-left: 20px;
  869.     border-left: 4px solid #3498db;
  870. }
  871. .kb-category-description {
  872.     font-size: 14px;
  873.     color: #7f8c8d;
  874.     margin: 0 0 20px 20px;
  875. }
  876. .kb-category-articles {
  877.     padding-left: 20px;
  878. }
  879. .kb-direct-articles-section {
  880.     margin-top: 40px;
  881.     padding-top: 40px;
  882.     border-top: 1px solid #ecf0f1;
  883. }
  884. /* Asegurar espaciado entre artículos */
  885. .kb-article-display {
  886.     margin-bottom: 60px;
  887.     padding-bottom: 40px;
  888.     border-bottom: 1px solid #f0f0f0;
  889. }
  890. .kb-article-display:last-child {
  891.     border-bottom: none;
  892.     margin-bottom: 0;
  893. }
  894. /* Highlight para artículo activo */
  895. .kb-article-display.active {
  896.     background: #f8f9fa;
  897.     padding: 30px;
  898.     border-radius: 8px;
  899.     border-left: 4px solid #3498db;
  900.     margin-left: -30px;
  901.     padding-left: 30px;
  902. }
  903. .kb-loading {
  904.     padding: 40px;
  905.     text-align: center;
  906.     color: #7f8c8d;
  907.     font-size: 16px;
  908. }
  909. .kb-welcome-screen {
  910.     display: flex;
  911.     align-items: flex-start;
  912.     justify-content: center;
  913.     min-height: calc(100vh - 250px);
  914.     padding: 60px 20px 40px 20px;
  915.     width: 100%;
  916.     box-sizing: border-box;
  917. }
  918. .kb-welcome-content {
  919.     text-align: center;
  920.     max-width: 600px;
  921.     width: 100%;
  922.     padding: 20px;
  923.     box-sizing: border-box;
  924. }
  925. .kb-welcome-content h1 {
  926.     font-size: 32px;
  927.     color: #2c3e50;
  928.     margin-bottom: 16px;
  929. }
  930. .kb-welcome-content > p {
  931.     font-size: 18px;
  932.     color: #7f8c8d;
  933.     margin-bottom: 40px;
  934. }
  935. .kb-stats {
  936.     display: flex;
  937.     justify-content: center;
  938.     gap: 40px;
  939.     margin-top: 40px;
  940. }
  941. .kb-stat-item {
  942.     display: flex;
  943.     flex-direction: column;
  944.     align-items: center;
  945. }
  946. .kb-stat-number {
  947.     font-size: 48px;
  948.     font-weight: bold;
  949.     color: #3498db;
  950.     line-height: 1;
  951. }
  952. .kb-stat-label {
  953.     font-size: 14px;
  954.     color: #7f8c8d;
  955.     margin-top: 8px;
  956. }
  957. /* Article Display Styles */
  958. .kb-article-display {
  959.     padding: 40px;
  960.     max-width: 900px;
  961.     margin: 0 auto;
  962. }
  963. .kb-article-header {
  964.     border-bottom: 2px solid #ecf0f1;
  965.     padding-bottom: 20px;
  966.     margin-bottom: 30px;
  967. }
  968. .kb-article-header h1 {
  969.     font-size: 32px;
  970.     color: #2c3e50;
  971.     margin: 0 0 16px 0;
  972.     line-height: 1.3;
  973. }
  974. .kb-article-meta {
  975.     display: flex;
  976.     gap: 20px;
  977.     font-size: 14px;
  978.     color: #7f8c8d;
  979. }
  980. .kb-article-author {
  981.     font-weight: 500;
  982. }
  983. .kb-article-date {
  984.     color: #95a5a6;
  985. }
  986. .kb-article-body {
  987.     font-size: 16px;
  988.     line-height: 1.8;
  989.     color: #34495e;
  990. }
  991. .kb-article-body h2 {
  992.     font-size: 24px;
  993.     color: #2c3e50;
  994.     margin-top: 32px;
  995.     margin-bottom: 16px;
  996. }
  997. .kb-article-body h3 {
  998.     font-size: 20px;
  999.     color: #34495e;
  1000.     margin-top: 24px;
  1001.     margin-bottom: 12px;
  1002. }
  1003. .kb-article-body p {
  1004.     margin-bottom: 16px;
  1005. }
  1006. .kb-article-body ul,
  1007. .kb-article-body ol {
  1008.     margin-bottom: 16px;
  1009.     padding-left: 30px;
  1010. }
  1011. .kb-article-body li {
  1012.     margin-bottom: 8px;
  1013. }
  1014. .kb-article-body code {
  1015.     background: #f4f4f4;
  1016.     padding: 2px 6px;
  1017.     border-radius: 3px;
  1018.     font-family: 'Courier New', monospace;
  1019.     font-size: 14px;
  1020. }
  1021. .kb-article-body pre {
  1022.     background: #2c3e50;
  1023.     color: #ecf0f1;
  1024.     padding: 16px;
  1025.     border-radius: 4px;
  1026.     overflow-x: auto;
  1027.     margin-bottom: 16px;
  1028. }
  1029. .kb-article-body pre code {
  1030.     background: transparent;
  1031.     padding: 0;
  1032.     color: inherit;
  1033. }
  1034. .kb-article-body img {
  1035.     max-width: 100%;
  1036.     height: auto;
  1037.     border-radius: 4px;
  1038.     margin: 20px 0;
  1039. }
  1040. .kb-article-body table {
  1041.     width: 100%;
  1042.     border-collapse: collapse;
  1043.     margin: 20px 0;
  1044. }
  1045. .kb-article-body table th,
  1046. .kb-article-body table td {
  1047.     padding: 12px;
  1048.     border: 1px solid #ddd;
  1049.     text-align: left;
  1050. }
  1051. .kb-article-body table th {
  1052.     background: #f8f9fa;
  1053.     font-weight: 600;
  1054. }
  1055. .kb-article-body blockquote {
  1056.     border-left: 4px solid #3498db;
  1057.     padding-left: 16px;
  1058.     margin: 20px 0;
  1059.     color: #7f8c8d;
  1060.     font-style: italic;
  1061. }
  1062. /* Loading State */
  1063. .kb-loading {
  1064.     display: flex;
  1065.     align-items: center;
  1066.     justify-content: center;
  1067.     min-height: 400px;
  1068.     font-size: 18px;
  1069.     color: #7f8c8d;
  1070. }
  1071. .kb-loading::before {
  1072.     content: '';
  1073.     width: 40px;
  1074.     height: 40px;
  1075.     border: 4px solid #ecf0f1;
  1076.     border-top-color: #3498db;
  1077.     border-radius: 50%;
  1078.     animation: spin 1s linear infinite;
  1079.     margin-right: 16px;
  1080. }
  1081. @keyframes spin {
  1082.     to { transform: rotate(360deg); }
  1083. }
  1084. /* Responsive */
  1085. @media (max-width: 768px) {
  1086.     .modern-kb-wrapper {
  1087.         flex-direction: column;
  1088.     }
  1089.     
  1090.     .modern-kb-sidebar {
  1091.         width: 100%;
  1092.         max-height: 300px;
  1093.     }
  1094.     
  1095.     .modern-kb-content {
  1096.         max-height: none;
  1097.     }
  1098. }
  1099. </style>
  1100. <script>
  1101. (function() {
  1102.     'use strict';
  1103.     
  1104.     // Función para inicializar todos los event listeners
  1105.     function initializeKB() {
  1106.         console.log('Initializing Knowledge Base...');
  1107.         
  1108.         // Debug: Log structure data
  1109.         const nav = document.getElementById('kb-navigation');
  1110.         if (nav) {
  1111.             const folders = nav.querySelectorAll('.modern-kb-folder-section');
  1112.             console.log('Total folders found in DOM:', folders.length);
  1113.             
  1114.             folders.forEach(function(folder, index) {
  1115.                 const folderHeader = folder.querySelector('.modern-kb-folder-header');
  1116.                 const folderName = folderHeader ? folderHeader.querySelector('.folder-name').textContent : 'Unknown';
  1117.                 const categories = folder.querySelectorAll('.modern-kb-category-section');
  1118.                 const directArticles = folder.querySelectorAll('.modern-kb-direct-articles');
  1119.                 console.log(`Folder ${index + 1}: "${folderName}" - Categories: ${categories.length}, Direct Articles sections: ${directArticles.length}`);
  1120.             });
  1121.         }
  1122.         
  1123.         // Toggle folder expansion
  1124.         const folderHeaders = document.querySelectorAll('.modern-kb-folder-header');
  1125.         console.log('Found folder headers:', folderHeaders.length);
  1126.         
  1127.         folderHeaders.forEach(function(header) {
  1128.             header.addEventListener('click', function(e) {
  1129.                 e.preventDefault();
  1130.                 e.stopPropagation();
  1131.                 console.log('Folder header clicked:', this.dataset.folderId);
  1132.                 
  1133.                 const folderId = this.dataset.folderId;
  1134.                 const content = document.getElementById('folder-' + folderId);
  1135.                 
  1136.                 if (!content) {
  1137.                     console.error('Folder content not found for ID:', folderId);
  1138.                     return;
  1139.                 }
  1140.                 
  1141.                 const isExpanded = content.classList.contains('expanded');
  1142.                 console.log('Current state - isExpanded:', isExpanded);
  1143.                 console.log('Content scrollHeight:', content.scrollHeight);
  1144.                 
  1145.                 // Toggle this folder
  1146.                 this.classList.toggle('active');
  1147.                 
  1148.                 // Force toggle with direct style manipulation
  1149.                 if (isExpanded) {
  1150.                     // Collapse
  1151.                     content.classList.remove('expanded');
  1152.                     content.style.maxHeight = '0px';
  1153.                     content.style.opacity = '0';
  1154.                     content.style.paddingTop = '0px';
  1155.                     content.style.paddingBottom = '0px';
  1156.                     content.style.overflow = 'hidden';
  1157.                     content.style.marginTop = '0';
  1158.                     content.style.marginBottom = '0';
  1159.                     console.log('Folder collapsed');
  1160.                 } else {
  1161.                     // Expand
  1162.                     content.classList.add('expanded');
  1163.                     
  1164.                     // First, reset all styles to ensure clean state
  1165.                     content.style.opacity = '1';
  1166.                     content.style.paddingTop = '10px';
  1167.                     content.style.paddingBottom = '10px';
  1168.                     content.style.overflow = 'hidden';
  1169.                     
  1170.                     // Temporarily remove max-height restriction to measure natural height
  1171.                     const originalMaxHeight = content.style.maxHeight;
  1172.                     content.style.maxHeight = 'none';
  1173.                     content.style.height = 'auto';
  1174.                     
  1175.                     // Force a reflow to ensure layout updates
  1176.                     void content.offsetHeight;
  1177.                     
  1178.                     // Now measure the natural height with padding
  1179.                     const naturalHeight = content.scrollHeight;
  1180.                     console.log('Natural height (with padding):', naturalHeight);
  1181.                     
  1182.                     // Calculate total height needed (add buffer for safety)
  1183.                     const buffer = 50; // Extra buffer to prevent cutting off content
  1184.                     const finalHeight = naturalHeight + buffer;
  1185.                     
  1186.                     // Apply the max-height for smooth transition
  1187.                     content.style.maxHeight = finalHeight + 'px';
  1188.                     content.style.height = 'auto';
  1189.                     
  1190.                     // Force another reflow to ensure layout updates and push elements down
  1191.                     void content.offsetHeight;
  1192.                     
  1193.                     // After transition completes, ensure overflow is visible
  1194.                     setTimeout(function() {
  1195.                         if (content.classList.contains('expanded')) {
  1196.                             // Keep overflow hidden to prevent content from spilling out
  1197.                             // but allow enough height for all content
  1198.                             const actualHeight = content.scrollHeight;
  1199.                             if (actualHeight > finalHeight - buffer) {
  1200.                                 content.style.maxHeight = (actualHeight + buffer) + 'px';
  1201.                             }
  1202.                         }
  1203.                     }, 350);
  1204.                     
  1205.                     console.log('Applied maxHeight:', content.style.maxHeight);
  1206.                     console.log('Content visible:', content.style.opacity);
  1207.                     console.log('Children count:', content.children.length);
  1208.                     console.log('Final height:', finalHeight);
  1209.                 }
  1210.             });
  1211.         });
  1212.         
  1213.         // Toggle category expansion and load articles - Using event delegation
  1214.         // Reutilizar nav que ya fue declarado arriba
  1215.         if (nav) {
  1216.             nav.addEventListener('click', function(e) {
  1217.                 console.log('Click detected in nav:', e.target);
  1218.                 
  1219.                 // First check if it's a category header or any child element
  1220.                 const categoryHeader = e.target.closest('.modern-kb-category-header');
  1221.                 if (categoryHeader && categoryHeader.dataset.categoryId) {
  1222.                     e.preventDefault();
  1223.                     e.stopPropagation();
  1224.                     
  1225.                     const categoryId = categoryHeader.dataset.categoryId;
  1226.                     console.log('Category header clicked:', categoryId);
  1227.                     
  1228.                     // Handle both regular categories and direct articles
  1229.                     let articlesList = document.getElementById('category-' + categoryId);
  1230.                     
  1231.                     // If not found, try direct articles format
  1232.                     if (!articlesList && categoryId.startsWith('direct-')) {
  1233.                         const folderId = categoryId.replace('direct-', '');
  1234.                         articlesList = document.getElementById('category-direct-' + folderId);
  1235.                     }
  1236.                     
  1237.                     if (articlesList) {
  1238.                         // Check current visibility state
  1239.                         const computedStyle = window.getComputedStyle(articlesList);
  1240.                         const isCurrentlyVisible = computedStyle.display !== 'none' && computedStyle.visibility !== 'hidden';
  1241.                         
  1242.                         // Find parent folder content to recalculate height
  1243.                         const folderContent = articlesList.closest('.modern-kb-folder-content');
  1244.                         
  1245.                         if (isCurrentlyVisible) {
  1246.                             // Hide
  1247.                             articlesList.style.setProperty('display', 'none', 'important');
  1248.                             articlesList.style.setProperty('visibility', 'hidden', 'important');
  1249.                             categoryHeader.classList.remove('active');
  1250.                             console.log('Category collapsed');
  1251.                             
  1252.                             // Recalculate parent folder height after hiding articles
  1253.                             if (folderContent && folderContent.classList.contains('expanded')) {
  1254.                                 setTimeout(function() {
  1255.                                     const naturalHeight = folderContent.scrollHeight;
  1256.                                     const buffer = 50;
  1257.                                     folderContent.style.maxHeight = (naturalHeight + buffer) + 'px';
  1258.                                     console.log('Recalculated folder height after collapse:', naturalHeight + buffer);
  1259.                                 }, 50);
  1260.                             }
  1261.                         } else {
  1262.                             // Show
  1263.                             articlesList.style.setProperty('display', 'block', 'important');
  1264.                             articlesList.style.setProperty('visibility', 'visible', 'important');
  1265.                             articlesList.style.setProperty('opacity', '1', 'important');
  1266.                             categoryHeader.classList.add('active');
  1267.                             
  1268.                             const articleCount = articlesList.querySelectorAll('.kb-article-link').length;
  1269.                             console.log('Category expanded, articles visible:', articleCount, 'articles');
  1270.                             
  1271.                             // Recalculate parent folder height after showing articles
  1272.                             if (folderContent && folderContent.classList.contains('expanded')) {
  1273.                                 setTimeout(function() {
  1274.                                     const naturalHeight = folderContent.scrollHeight;
  1275.                                     const buffer = 50;
  1276.                                     folderContent.style.maxHeight = (naturalHeight + buffer) + 'px';
  1277.                                     console.log('Recalculated folder height after expand:', naturalHeight + buffer);
  1278.                                 }, 50);
  1279.                             }
  1280.                         }
  1281.                     } else {
  1282.                         console.error('Articles list not found for category:', categoryId);
  1283.                     }
  1284.                     return; // Exit early to prevent article link handler
  1285.                 }
  1286.                 
  1287.                 // Then check if it's an article link
  1288.                 const articleLink = e.target.closest('.kb-article-link');
  1289.                 if (articleLink) {
  1290.                     e.preventDefault();
  1291.                     e.stopPropagation();
  1292.                     
  1293.                     console.log('Article link clicked');
  1294.                     
  1295.                     // Remove active class from all links and articles
  1296.                     document.querySelectorAll('.kb-article-link').forEach(function(l) {
  1297.                         l.classList.remove('active');
  1298.                     });
  1299.                     document.querySelectorAll('.kb-article-display').forEach(function(a) {
  1300.                         a.classList.remove('active');
  1301.                     });
  1302.                     
  1303.                     // Add active class to clicked link
  1304.                     articleLink.classList.add('active');
  1305.                     
  1306.                     const articleSlug = articleLink.dataset.articleSlug;
  1307.                     const articleId = articleLink.dataset.articleId;
  1308.                     
  1309.                     console.log('Scrolling to article:', articleSlug);
  1310.                     
  1311.                     if (!articleSlug) {
  1312.                         console.error('No article slug found');
  1313.                         return;
  1314.                     }
  1315.                     
  1316.                     // Update URL without reload
  1317.                     const url = new URL(window.location);
  1318.                     url.searchParams.set('article', articleSlug);
  1319.                     window.history.pushState({article: articleSlug}, '', url);
  1320.                     
  1321.                     // Find the article in the main content area
  1322.                     const articleElement = document.getElementById('article-' + articleSlug);
  1323.                     const contentArea = document.querySelector('.modern-kb-content');
  1324.                     
  1325.                     if (articleElement && contentArea) {
  1326.                         // Add active class to highlight the article
  1327.                         articleElement.classList.add('active');
  1328.                         
  1329.                         // Calculate scroll position (offset from top of content area)
  1330.                         const contentRect = contentArea.getBoundingClientRect();
  1331.                         const articleRect = articleElement.getBoundingClientRect();
  1332.                         const scrollTop = contentArea.scrollTop;
  1333.                         const articleTop = articleRect.top - contentRect.top + scrollTop;
  1334.                         
  1335.                         // Scroll to article with smooth behavior
  1336.                         contentArea.scrollTo({
  1337.                             top: articleTop - 20, // 20px offset from top
  1338.                             behavior: 'smooth'
  1339.                         });
  1340.                         
  1341.                         console.log('Scrolled to article:', articleSlug);
  1342.                     } else {
  1343.                         console.error('Article element not found:', 'article-' + articleSlug);
  1344.                         // If article not found, scroll to welcome screen
  1345.                         const welcomeScreen = document.getElementById('welcome-screen');
  1346.                         if (welcomeScreen && contentArea) {
  1347.                             contentArea.scrollTo({
  1348.                                 top: 0,
  1349.                                 behavior: 'smooth'
  1350.                             });
  1351.                         }
  1352.                     }
  1353.                 }
  1354.             });
  1355.         }
  1356.         
  1357.         // Count article links after a short delay to ensure all are rendered
  1358.         setTimeout(function() {
  1359.             console.log('Found article links:', document.querySelectorAll('.kb-article-link').length);
  1360.             console.log('Found category headers:', document.querySelectorAll('.modern-kb-category-header').length);
  1361.         }, 500);
  1362.         
  1363.         // Handle browser back/forward buttons
  1364.         window.addEventListener('popstate', function(e) {
  1365.             if (e.state && e.state.article) {
  1366.                 const link = document.querySelector('[data-article-slug="' + e.state.article + '"]');
  1367.                 if (link) {
  1368.                     link.click();
  1369.                 }
  1370.             }
  1371.         });
  1372.         
  1373.         // Handle article selection from URL parameter
  1374.         const urlParams = new URLSearchParams(window.location.search);
  1375.         const articleParam = urlParams.get('article');
  1376.         if (articleParam) {
  1377.             setTimeout(function() {
  1378.                 const articleElement = document.getElementById('article-' + articleParam);
  1379.                 const activeLink = document.querySelector('[data-article-slug="' + articleParam + '"]');
  1380.                 const contentArea = document.querySelector('.modern-kb-content');
  1381.                 
  1382.                 if (articleElement && contentArea) {
  1383.                     // Add active classes
  1384.                     if (activeLink) {
  1385.                         activeLink.classList.add('active');
  1386.                     }
  1387.                     articleElement.classList.add('active');
  1388.                     
  1389.                     // Expand parent folder and category
  1390.                     if (activeLink) {
  1391.                         let articlesList = activeLink.closest('.modern-kb-articles-list');
  1392.                         if (articlesList) {
  1393.                             articlesList.style.setProperty('display', 'block', 'important');
  1394.                             let categoryHeader = articlesList.previousElementSibling;
  1395.                             if (categoryHeader && categoryHeader.classList.contains('modern-kb-category-header')) {
  1396.                                 categoryHeader.classList.add('active');
  1397.                                 
  1398.                                 // Expand parent folder
  1399.                                 let folderContent = categoryHeader.closest('.modern-kb-folder-content');
  1400.                                 if (folderContent) {
  1401.                                     let folderHeader = folderContent.previousElementSibling;
  1402.                                     if (folderHeader && folderHeader.classList.contains('modern-kb-folder-header')) {
  1403.                                         folderHeader.classList.add('active');
  1404.                                         folderContent.classList.add('expanded');
  1405.                                         folderContent.style.maxHeight = '9999px';
  1406.                                         folderContent.style.opacity = '1';
  1407.                                         folderContent.style.overflow = 'visible';
  1408.                                         folderContent.style.paddingTop = '10px';
  1409.                                         folderContent.style.paddingBottom = '10px';
  1410.                                     }
  1411.                                 }
  1412.                             }
  1413.                         }
  1414.                     }
  1415.                     
  1416.                     // Scroll to article
  1417.                     const contentRect = contentArea.getBoundingClientRect();
  1418.                     const articleRect = articleElement.getBoundingClientRect();
  1419.                     const scrollTop = contentArea.scrollTop;
  1420.                     const articleTop = articleRect.top - contentRect.top + scrollTop;
  1421.                     
  1422.                     contentArea.scrollTo({
  1423.                         top: articleTop - 20,
  1424.                         behavior: 'smooth'
  1425.                     });
  1426.                 }
  1427.             }, 300);
  1428.         }
  1429.         
  1430.         // Auto-expand selected topic folder and category, then scroll
  1431.         {% if selectedTopic %}
  1432.             setTimeout(function() {
  1433.                 const topicId = {{ selectedTopic.id }};
  1434.                 const firstCategoryId = {{ selectedTopic.firstCategoryId ?: 'null' }};
  1435.                 
  1436.                 // Hide welcome screen
  1437.                 const welcomeScreen = document.getElementById('welcome-screen');
  1438.                 if (welcomeScreen) {
  1439.                     welcomeScreen.style.display = 'none';
  1440.                 }
  1441.                 
  1442.                 // Find and expand the folder (solution)
  1443.                 const folderHeader = document.querySelector('.modern-kb-folder-header[data-folder-id="' + topicId + '"]');
  1444.                 if (folderHeader) {
  1445.                     const folderContent = document.getElementById('folder-' + topicId);
  1446.                     
  1447.                     if (folderContent) {
  1448.                         // Expand folder
  1449.                         folderHeader.classList.add('active');
  1450.                         folderContent.classList.add('expanded');
  1451.                         folderContent.style.opacity = '1';
  1452.                         folderContent.style.paddingTop = '10px';
  1453.                         folderContent.style.paddingBottom = '10px';
  1454.                         folderContent.style.overflow = 'hidden';
  1455.                         
  1456.                         // Calculate natural height
  1457.                         folderContent.style.maxHeight = 'none';
  1458.                         const naturalHeight = folderContent.scrollHeight;
  1459.                         const buffer = 50;
  1460.                         folderContent.style.maxHeight = (naturalHeight + buffer) + 'px';
  1461.                         
  1462.                         console.log('Expanded folder:', topicId);
  1463.                         
  1464.                         // If there's a first category, expand it too
  1465.                         if (firstCategoryId) {
  1466.                             setTimeout(function() {
  1467.                                 const categoryHeader = document.querySelector('.modern-kb-category-header[data-category-id="' + firstCategoryId + '"]');
  1468.                                 const articlesList = document.getElementById('category-' + firstCategoryId);
  1469.                                 
  1470.                                 if (categoryHeader && articlesList) {
  1471.                                     articlesList.style.setProperty('display', 'block', 'important');
  1472.                                     articlesList.style.setProperty('visibility', 'visible', 'important');
  1473.                                     articlesList.style.setProperty('opacity', '1', 'important');
  1474.                                     categoryHeader.classList.add('active');
  1475.                                     
  1476.                                     console.log('Expanded category:', firstCategoryId);
  1477.                                     
  1478.                                     // Scroll to the category section in main content
  1479.                                     setTimeout(function() {
  1480.                                         const categorySection = document.querySelector('.kb-category-content-section[data-category-id="' + firstCategoryId + '"]');
  1481.                                         const contentArea = document.querySelector('.modern-kb-content');
  1482.                                         
  1483.                                         if (categorySection && contentArea) {
  1484.                                             // Wait a bit more for layout to settle
  1485.                                             setTimeout(function() {
  1486.                                                 const contentRect = contentArea.getBoundingClientRect();
  1487.                                                 const sectionRect = categorySection.getBoundingClientRect();
  1488.                                                 const scrollTop = contentArea.scrollTop;
  1489.                                                 const sectionTop = sectionRect.top - contentRect.top + scrollTop;
  1490.                                                 
  1491.                                                 contentArea.scrollTo({
  1492.                                                     top: Math.max(0, sectionTop - 120), // 120px offset from top
  1493.                                                     behavior: 'smooth'
  1494.                                                 });
  1495.                                                 
  1496.                                                 console.log('Scrolled to category section');
  1497.                                             }, 100);
  1498.                                         }
  1499.                                     }, 400);
  1500.                                 }
  1501.                             }, 300);
  1502.                         } else {
  1503.                             // If no category, scroll to the folder section
  1504.                             setTimeout(function() {
  1505.                                 const folderSection = document.querySelector('.kb-folder-content-section[data-folder-id="' + topicId + '"]');
  1506.                                 const contentArea = document.querySelector('.modern-kb-content');
  1507.                                 
  1508.                                 if (folderSection && contentArea) {
  1509.                                     setTimeout(function() {
  1510.                                         const contentRect = contentArea.getBoundingClientRect();
  1511.                                         const sectionRect = folderSection.getBoundingClientRect();
  1512.                                         const scrollTop = contentArea.scrollTop;
  1513.                                         const sectionTop = sectionRect.top - contentRect.top + scrollTop;
  1514.                                         
  1515.                                         contentArea.scrollTo({
  1516.                                             top: Math.max(0, sectionTop - 120),
  1517.                                             behavior: 'smooth'
  1518.                                         });
  1519.                                         
  1520.                                         console.log('Scrolled to folder section');
  1521.                                     }, 100);
  1522.                                 }
  1523.                             }, 300);
  1524.                         }
  1525.                     }
  1526.                 } else {
  1527.                     console.warn('Folder not found for topic ID:', topicId);
  1528.                 }
  1529.             }, 500);
  1530.         {% elseif not selectedArticle %}
  1531.             // Auto-expand first folder on load if no article is selected and no topic
  1532.             const firstFolder = document.querySelector('.modern-kb-folder-header');
  1533.             if (firstFolder) {
  1534.                 setTimeout(function() {
  1535.                     firstFolder.click();
  1536.                 }, 100);
  1537.             }
  1538.         {% endif %}
  1539.         
  1540.         console.log('Knowledge Base initialized successfully');
  1541.     }
  1542.     
  1543.     // Search functionality
  1544.     function initializeSearch() {
  1545.         const searchInput = document.getElementById('kb-search-input');
  1546.         const searchClear = document.getElementById('kb-search-clear');
  1547.         const resultsCount = document.getElementById('kb-search-results-count');
  1548.         const resultsNumber = document.getElementById('kb-results-number');
  1549.         
  1550.         if (!searchInput) return;
  1551.         
  1552.         // Function to highlight text
  1553.         function highlightText(text, searchTerm) {
  1554.             if (!searchTerm) return text;
  1555.             const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
  1556.             return text.replace(regex, '<span class="kb-search-highlight">$1</span>');
  1557.         }
  1558.         
  1559.         // Function to perform search
  1560.         function performSearch(searchTerm) {
  1561.             const term = searchTerm.trim().toLowerCase();
  1562.             let matchCount = 0;
  1563.             
  1564.             // Show/hide clear button
  1565.             if (term.length > 0) {
  1566.                 searchClear.style.display = 'block';
  1567.                 resultsCount.style.display = 'block';
  1568.             } else {
  1569.                 searchClear.style.display = 'none';
  1570.                 resultsCount.style.display = 'none';
  1571.             }
  1572.             
  1573.             if (term.length === 0) {
  1574.                 // Reset all - show everything
  1575.                 document.querySelectorAll('.modern-kb-folder-section').forEach(function(section) {
  1576.                     section.classList.remove('hidden-by-search', 'visible-by-search');
  1577.                 });
  1578.                 document.querySelectorAll('.modern-kb-category-section').forEach(function(section) {
  1579.                     section.classList.remove('hidden-by-search', 'visible-by-search');
  1580.                 });
  1581.                 document.querySelectorAll('.modern-kb-article-item').forEach(function(item) {
  1582.                     item.classList.remove('hidden-by-search');
  1583.                     const link = item.querySelector('.kb-article-link');
  1584.                     if (link && link.dataset.originalText) {
  1585.                         link.innerHTML = link.dataset.originalText; // Restore original text
  1586.                     }
  1587.                 });
  1588.                 document.querySelectorAll('.kb-article-display').forEach(function(article) {
  1589.                     article.classList.remove('hidden-by-search');
  1590.                     const header = article.querySelector('.kb-article-header h1');
  1591.                     if (header) {
  1592.                         // Store original text if not already stored
  1593.                         if (!header.dataset.originalText) {
  1594.                             header.dataset.originalText = header.textContent;
  1595.                         }
  1596.                         header.innerHTML = header.dataset.originalText; // Restore original text
  1597.                     }
  1598.                 });
  1599.                 // Restore category names
  1600.                 document.querySelectorAll('.category-name').forEach(function(catName) {
  1601.                     if (catName.dataset.originalText) {
  1602.                         catName.innerHTML = catName.dataset.originalText;
  1603.                     }
  1604.                 });
  1605.                 resultsNumber.textContent = '0';
  1606.                 return;
  1607.             }
  1608.             
  1609.             // First, search in category names (sidebar)
  1610.             const categoryMatches = new Set();
  1611.             document.querySelectorAll('.category-name').forEach(function(catName) {
  1612.                 // Store original text if not already stored
  1613.                 if (!catName.dataset.originalText) {
  1614.                     catName.dataset.originalText = catName.textContent;
  1615.                 }
  1616.                 
  1617.                 const originalText = catName.dataset.originalText;
  1618.                 const categoryName = originalText.toLowerCase();
  1619.                 
  1620.                 if (categoryName.includes(term)) {
  1621.                     // Category name matches - mark it and show all its articles
  1622.                     const catSection = catName.closest('.modern-kb-category-section');
  1623.                     if (catSection) {
  1624.                         categoryMatches.add(catSection);
  1625.                         // Show all articles in this category
  1626.                         const articles = catSection.querySelectorAll('.modern-kb-article-item');
  1627.                         articles.forEach(function(article) {
  1628.                             article.classList.remove('hidden-by-search');
  1629.                         });
  1630.                         matchCount += articles.length;
  1631.                     }
  1632.                     
  1633.                     // Highlight the matching text in the category name
  1634.                     catName.innerHTML = highlightText(originalText, searchTerm);
  1635.                 } else {
  1636.                     // Restore original text without highlights
  1637.                     catName.innerHTML = originalText;
  1638.                 }
  1639.             });
  1640.             
  1641.             // Search in sidebar article links
  1642.             document.querySelectorAll('.kb-article-link').forEach(function(link) {
  1643.                 // Store original text if not already stored
  1644.                 if (!link.dataset.originalText) {
  1645.                     link.dataset.originalText = link.textContent;
  1646.                 }
  1647.                 
  1648.                 const originalText = link.dataset.originalText;
  1649.                 const articleName = originalText.toLowerCase();
  1650.                 const articleItem = link.closest('.modern-kb-article-item');
  1651.                 
  1652.                 // Check if this article is in a matching category
  1653.                 const catSection = articleItem.closest('.modern-kb-category-section');
  1654.                 const isInMatchingCategory = catSection && categoryMatches.has(catSection);
  1655.                 
  1656.                 if (articleName.includes(term) || isInMatchingCategory) {
  1657.                     articleItem.classList.remove('hidden-by-search');
  1658.                     if (!isInMatchingCategory) {
  1659.                         matchCount++;
  1660.                     }
  1661.                     
  1662.                     // Highlight the matching text in the link
  1663.                     if (articleName.includes(term)) {
  1664.                         link.innerHTML = highlightText(originalText, searchTerm);
  1665.                     } else {
  1666.                         link.innerHTML = originalText;
  1667.                     }
  1668.                 } else {
  1669.                     articleItem.classList.add('hidden-by-search');
  1670.                     // Restore original text without highlights
  1671.                     link.innerHTML = originalText;
  1672.                 }
  1673.             });
  1674.             
  1675.             // Search in main content articles
  1676.             document.querySelectorAll('.kb-article-display').forEach(function(article) {
  1677.                 const header = article.querySelector('.kb-article-header h1');
  1678.                 const body = article.querySelector('.kb-article-body');
  1679.                 
  1680.                 // Store original header text if not already stored
  1681.                 if (header && !header.dataset.originalText) {
  1682.                     header.dataset.originalText = header.textContent;
  1683.                 }
  1684.                 
  1685.                 const originalHeaderText = header && header.dataset.originalText ? header.dataset.originalText : '';
  1686.                 const articleName = originalHeaderText.toLowerCase();
  1687.                 const articleContent = body ? body.textContent.toLowerCase() : '';
  1688.                 
  1689.                 if (articleName.includes(term) || articleContent.includes(term)) {
  1690.                     article.classList.remove('hidden-by-search');
  1691.                     matchCount++;
  1692.                     
  1693.                     // Highlight in header
  1694.                     if (header && articleName.includes(term)) {
  1695.                         header.innerHTML = highlightText(originalHeaderText, searchTerm);
  1696.                     } else if (header) {
  1697.                         // Restore original if no match in header
  1698.                         header.innerHTML = originalHeaderText;
  1699.                     }
  1700.                 } else {
  1701.                     article.classList.add('hidden-by-search');
  1702.                     // Restore original header text
  1703.                     if (header && header.dataset.originalText) {
  1704.                         header.innerHTML = header.dataset.originalText;
  1705.                     }
  1706.                 }
  1707.             });
  1708.             
  1709.             // Show/hide folders and categories based on matches
  1710.             document.querySelectorAll('.modern-kb-folder-section').forEach(function(folderSection) {
  1711.                 const folderContent = folderSection.querySelector('.modern-kb-folder-content');
  1712.                 const visibleArticles = folderContent ? 
  1713.                     folderContent.querySelectorAll('.modern-kb-article-item:not(.hidden-by-search)') : [];
  1714.                 
  1715.                 // Check if category has visible articles or matching category names
  1716.                 let hasVisibleContent = visibleArticles.length > 0;
  1717.                 if (!hasVisibleContent && folderContent) {
  1718.                     folderContent.querySelectorAll('.modern-kb-category-section').forEach(function(catSection) {
  1719.                         const catArticles = catSection.querySelectorAll('.modern-kb-article-item:not(.hidden-by-search)');
  1720.                         const catName = catSection.querySelector('.category-name');
  1721.                         const categoryNameMatches = catName && catName.textContent.toLowerCase().includes(term);
  1722.                         
  1723.                         if (catArticles.length > 0 || categoryNameMatches) {
  1724.                             hasVisibleContent = true;
  1725.                         }
  1726.                     });
  1727.                 }
  1728.                 
  1729.                 if (hasVisibleContent) {
  1730.                     folderSection.classList.remove('hidden-by-search');
  1731.                     folderSection.classList.add('visible-by-search');
  1732.                     
  1733.                     // Auto-expand folder if it has matches
  1734.                     if (folderContent && !folderContent.classList.contains('expanded')) {
  1735.                         const folderHeader = folderSection.querySelector('.modern-kb-folder-header');
  1736.                         if (folderHeader) {
  1737.                             folderHeader.classList.add('active');
  1738.                             folderContent.classList.add('expanded');
  1739.                             folderContent.style.maxHeight = '9999px';
  1740.                             folderContent.style.opacity = '1';
  1741.                             folderContent.style.paddingTop = '10px';
  1742.                             folderContent.style.paddingBottom = '10px';
  1743.                         }
  1744.                     }
  1745.                 } else {
  1746.                     folderSection.classList.add('hidden-by-search');
  1747.                     folderSection.classList.remove('visible-by-search');
  1748.                 }
  1749.             });
  1750.             
  1751.             // Show/hide categories based on matches
  1752.             document.querySelectorAll('.modern-kb-category-section').forEach(function(catSection) {
  1753.                 const visibleArticles = catSection.querySelectorAll('.modern-kb-article-item:not(.hidden-by-search)');
  1754.                 const catName = catSection.querySelector('.category-name');
  1755.                 const categoryNameMatches = catName && catName.textContent.toLowerCase().includes(term);
  1756.                 
  1757.                 if (visibleArticles.length > 0 || categoryNameMatches) {
  1758.                     catSection.classList.remove('hidden-by-search');
  1759.                     catSection.classList.add('visible-by-search');
  1760.                     
  1761.                     // Auto-expand category and show articles list
  1762.                     const articlesList = catSection.querySelector('.modern-kb-articles-list');
  1763.                     const categoryHeader = catSection.querySelector('.modern-kb-category-header');
  1764.                     
  1765.                     if (articlesList && categoryHeader) {
  1766.                         articlesList.style.setProperty('display', 'block', 'important');
  1767.                         articlesList.style.setProperty('visibility', 'visible', 'important');
  1768.                         articlesList.style.setProperty('opacity', '1', 'important');
  1769.                         categoryHeader.classList.add('active');
  1770.                     }
  1771.                 } else {
  1772.                     catSection.classList.add('hidden-by-search');
  1773.                     catSection.classList.remove('visible-by-search');
  1774.                 }
  1775.             });
  1776.             
  1777.             // Update results count
  1778.             resultsNumber.textContent = matchCount;
  1779.         }
  1780.         
  1781.         // Event listeners
  1782.         let searchTimeout;
  1783.         searchInput.addEventListener('input', function(e) {
  1784.             clearTimeout(searchTimeout);
  1785.             const term = e.target.value;
  1786.             
  1787.             // Debounce search for better performance
  1788.             searchTimeout = setTimeout(function() {
  1789.                 performSearch(term);
  1790.             }, 300);
  1791.         });
  1792.         
  1793.         searchInput.addEventListener('keydown', function(e) {
  1794.             if (e.key === 'Enter') {
  1795.                 e.preventDefault();
  1796.                 clearTimeout(searchTimeout);
  1797.                 performSearch(e.target.value);
  1798.             }
  1799.         });
  1800.         
  1801.         searchClear.addEventListener('click', function() {
  1802.             searchInput.value = '';
  1803.             searchInput.focus();
  1804.             performSearch('');
  1805.         });
  1806.         
  1807.         // Initial search if URL has search parameter
  1808.         const urlParams = new URLSearchParams(window.location.search);
  1809.         const searchParam = urlParams.get('search');
  1810.         if (searchParam) {
  1811.             searchInput.value = searchParam;
  1812.             performSearch(searchParam);
  1813.         }
  1814.     }
  1815.     
  1816.     // Content Search functionality
  1817.     function initializeContentSearch() {
  1818.         const contentSearchInput = document.getElementById('kb-content-search-input');
  1819.         const contentSearchClear = document.getElementById('kb-content-search-clear');
  1820.         const contentResultsCount = document.getElementById('kb-content-search-results-count');
  1821.         const contentResultsNumber = document.getElementById('kb-content-results-number');
  1822.         const welcomeScreen = document.getElementById('welcome-screen');
  1823.         
  1824.         if (!contentSearchInput) return;
  1825.         
  1826.         // Function to highlight text in content
  1827.         function highlightContentText(text, searchTerm) {
  1828.             if (!searchTerm) return text;
  1829.             const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
  1830.             return text.replace(regex, '<mark class="kb-content-search-highlight">$1</mark>');
  1831.         }
  1832.         
  1833.         // Function to perform content search
  1834.         function performContentSearch(searchTerm) {
  1835.             const term = searchTerm.trim().toLowerCase();
  1836.             let matchCount = 0;
  1837.             
  1838.             // Show/hide clear button and results count
  1839.             if (term.length > 0) {
  1840.                 contentSearchClear.style.display = 'block';
  1841.                 contentResultsCount.style.display = 'block';
  1842.             } else {
  1843.                 contentSearchClear.style.display = 'none';
  1844.                 contentResultsCount.style.display = 'none';
  1845.             }
  1846.             
  1847.             if (term.length === 0) {
  1848.                 // Reset all - show everything including welcome screen
  1849.                 document.querySelectorAll('.kb-article-display').forEach(function(article) {
  1850.                     article.classList.remove('hidden-by-content-search');
  1851.                     const header = article.querySelector('.kb-article-header h1');
  1852.                     if (header && header.dataset.originalText) {
  1853.                         header.innerHTML = header.dataset.originalText;
  1854.                     }
  1855.                     // Remove highlights from body content
  1856.                     const body = article.querySelector('.kb-article-body');
  1857.                     if (body && body.dataset.originalHtml) {
  1858.                         body.innerHTML = body.dataset.originalHtml;
  1859.                     }
  1860.                 });
  1861.                 document.querySelectorAll('.kb-folder-content-section').forEach(function(section) {
  1862.                     section.classList.remove('hidden-by-content-search');
  1863.                 });
  1864.                 document.querySelectorAll('.kb-category-content-section').forEach(function(section) {
  1865.                     section.classList.remove('hidden-by-content-search');
  1866.                 });
  1867.                 
  1868.                 // Restore category titles
  1869.                 document.querySelectorAll('.kb-category-title').forEach(function(catTitle) {
  1870.                     if (catTitle.dataset.originalText) {
  1871.                         catTitle.innerHTML = catTitle.dataset.originalText;
  1872.                     }
  1873.                 });
  1874.                 
  1875.                 // Show welcome screen
  1876.                 if (welcomeScreen) {
  1877.                     welcomeScreen.classList.remove('hidden-by-content-search');
  1878.                 }
  1879.                 
  1880.                 contentResultsNumber.textContent = '0';
  1881.                 return;
  1882.             }
  1883.             
  1884.             // Hide welcome screen when searching
  1885.             if (welcomeScreen) {
  1886.                 welcomeScreen.classList.add('hidden-by-content-search');
  1887.             }
  1888.             
  1889.             // First, search in category titles (main content)
  1890.             const categoryContentMatches = new Set();
  1891.             document.querySelectorAll('.kb-category-title').forEach(function(catTitle) {
  1892.                 // Store original text if not already stored
  1893.                 if (!catTitle.dataset.originalText) {
  1894.                     catTitle.dataset.originalText = catTitle.textContent;
  1895.                 }
  1896.                 
  1897.                 const originalText = catTitle.dataset.originalText;
  1898.                 const categoryName = originalText.toLowerCase();
  1899.                 
  1900.                 if (categoryName.includes(term)) {
  1901.                     // Category name matches - mark it and show all its articles
  1902.                     const catSection = catTitle.closest('.kb-category-content-section');
  1903.                     if (catSection) {
  1904.                         categoryContentMatches.add(catSection);
  1905.                         // Show all articles in this category
  1906.                         const articles = catSection.querySelectorAll('.kb-article-display');
  1907.                         articles.forEach(function(article) {
  1908.                             article.classList.remove('hidden-by-content-search');
  1909.                         });
  1910.                         matchCount += articles.length;
  1911.                     }
  1912.                     
  1913.                     // Highlight the matching text in the category title
  1914.                     catTitle.innerHTML = highlightContentText(originalText, searchTerm);
  1915.                 } else {
  1916.                     // Restore original text without highlights
  1917.                     catTitle.innerHTML = originalText;
  1918.                 }
  1919.             });
  1920.             
  1921.             // Search in all articles in the main content
  1922.             document.querySelectorAll('.kb-article-display').forEach(function(article) {
  1923.                 const header = article.querySelector('.kb-article-header h1');
  1924.                 const body = article.querySelector('.kb-article-body');
  1925.                 
  1926.                 // Check if this article is in a matching category
  1927.                 const catSection = article.closest('.kb-category-content-section');
  1928.                 const isInMatchingCategory = catSection && categoryContentMatches.has(catSection);
  1929.                 
  1930.                 // Store original header text if not already stored
  1931.                 if (header && !header.dataset.originalText) {
  1932.                     header.dataset.originalText = header.textContent;
  1933.                 }
  1934.                 
  1935.                 // Store original body HTML if not already stored
  1936.                 if (body && !body.dataset.originalHtml) {
  1937.                     body.dataset.originalHtml = body.innerHTML;
  1938.                 }
  1939.                 
  1940.                 const originalHeaderText = header && header.dataset.originalText ? header.dataset.originalText : '';
  1941.                 const articleName = originalHeaderText.toLowerCase();
  1942.                 const articleContent = body ? body.textContent.toLowerCase() : '';
  1943.                 
  1944.                 if (articleName.includes(term) || articleContent.includes(term) || isInMatchingCategory) {
  1945.                     article.classList.remove('hidden-by-content-search');
  1946.                     if (!isInMatchingCategory) {
  1947.                         matchCount++;
  1948.                     }
  1949.                     
  1950.                     // Highlight in header if matches
  1951.                     if (header && articleName.includes(term)) {
  1952.                         header.innerHTML = highlightContentText(originalHeaderText, searchTerm);
  1953.                     } else if (header) {
  1954.                         header.innerHTML = originalHeaderText;
  1955.                     }
  1956.                     
  1957.                     // Highlight in body content if matches
  1958.                     if (body && articleContent.includes(term) && body.dataset.originalHtml) {
  1959.                         // Simple approach: highlight text in HTML while preserving structure
  1960.                         // Escape special regex characters in search term
  1961.                         const escapedTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  1962.                         const regex = new RegExp(`(${escapedTerm})`, 'gi');
  1963.                         
  1964.                         // Replace text nodes only (preserve HTML tags)
  1965.                         // This is a simplified approach - replace in text content areas
  1966.                         let htmlContent = body.dataset.originalHtml;
  1967.                         // Only replace outside of HTML tags
  1968.                         htmlContent = htmlContent.replace(regex, function(match) {
  1969.                             // Check if we're inside an HTML tag
  1970.                             return '<mark class="kb-content-search-highlight">' + match + '</mark>';
  1971.                         });
  1972.                         
  1973.                         body.innerHTML = htmlContent;
  1974.                     } else if (body && body.dataset.originalHtml) {
  1975.                         body.innerHTML = body.dataset.originalHtml;
  1976.                     }
  1977.                 } else {
  1978.                     article.classList.add('hidden-by-content-search');
  1979.                     // Restore original content
  1980.                     if (header && header.dataset.originalText) {
  1981.                         header.innerHTML = header.dataset.originalText;
  1982.                     }
  1983.                     if (body && body.dataset.originalHtml) {
  1984.                         body.innerHTML = body.dataset.originalHtml;
  1985.                     }
  1986.                 }
  1987.             });
  1988.             
  1989.             // Hide/show folder and category sections based on visible articles or matching category names
  1990.             document.querySelectorAll('.kb-folder-content-section').forEach(function(folderSection) {
  1991.                 const visibleArticles = folderSection.querySelectorAll('.kb-article-display:not(.hidden-by-content-search)');
  1992.                 const matchingCategories = folderSection.querySelectorAll('.kb-category-title');
  1993.                 let hasMatchingCategory = false;
  1994.                 
  1995.                 matchingCategories.forEach(function(catTitle) {
  1996.                     if (catTitle.textContent.toLowerCase().includes(term)) {
  1997.                         hasMatchingCategory = true;
  1998.                     }
  1999.                 });
  2000.                 
  2001.                 if (visibleArticles.length > 0 || hasMatchingCategory) {
  2002.                     folderSection.classList.remove('hidden-by-content-search');
  2003.                 } else {
  2004.                     folderSection.classList.add('hidden-by-content-search');
  2005.                 }
  2006.             });
  2007.             
  2008.             document.querySelectorAll('.kb-category-content-section').forEach(function(catSection) {
  2009.                 const visibleArticles = catSection.querySelectorAll('.kb-article-display:not(.hidden-by-content-search)');
  2010.                 const catTitle = catSection.querySelector('.kb-category-title');
  2011.                 const categoryNameMatches = catTitle && catTitle.textContent.toLowerCase().includes(term);
  2012.                 
  2013.                 if (visibleArticles.length > 0 || categoryNameMatches) {
  2014.                     catSection.classList.remove('hidden-by-content-search');
  2015.                 } else {
  2016.                     catSection.classList.add('hidden-by-content-search');
  2017.                 }
  2018.             });
  2019.             
  2020.             // Update results count
  2021.             contentResultsNumber.textContent = matchCount;
  2022.         }
  2023.         
  2024.         // Event listeners
  2025.         let contentSearchTimeout;
  2026.         contentSearchInput.addEventListener('input', function(e) {
  2027.             clearTimeout(contentSearchTimeout);
  2028.             const term = e.target.value;
  2029.             
  2030.             // Debounce search for better performance
  2031.             contentSearchTimeout = setTimeout(function() {
  2032.                 performContentSearch(term);
  2033.             }, 300);
  2034.         });
  2035.         
  2036.         contentSearchInput.addEventListener('keydown', function(e) {
  2037.             if (e.key === 'Enter') {
  2038.                 e.preventDefault();
  2039.                 clearTimeout(contentSearchTimeout);
  2040.                 performContentSearch(e.target.value);
  2041.             }
  2042.         });
  2043.         
  2044.         contentSearchClear.addEventListener('click', function() {
  2045.             contentSearchInput.value = '';
  2046.             contentSearchInput.focus();
  2047.             performContentSearch('');
  2048.         });
  2049.     }
  2050.     
  2051.     // Initialize when DOM is ready (only once)
  2052.     let initialized = false;
  2053.     function initOnce() {
  2054.         if (!initialized) {
  2055.             initialized = true;
  2056.             initializeKB();
  2057.             initializeSearch();
  2058.             initializeContentSearch();
  2059.             
  2060.             // Scroll to container if topic is selected (after everything is initialized)
  2061.             {% if selectedTopic %}
  2062.             setTimeout(function() {
  2063.                 const kbContainer = document.getElementById('modern-kb-container');
  2064.                 if (kbContainer) {
  2065.                     const containerRect = kbContainer.getBoundingClientRect();
  2066.                     const scrollY = window.scrollY || window.pageYOffset;
  2067.                     const containerTop = containerRect.top + scrollY;
  2068.                     
  2069.                     window.scrollTo({
  2070.                         top: Math.max(0, containerTop - 20), // 20px offset from top
  2071.                         behavior: 'smooth'
  2072.                     });
  2073.                     
  2074.                     console.log('Scrolled page to modern-kb-container');
  2075.                 }
  2076.             }, 800); // Wait a bit more for all content to render
  2077.             {% endif %}
  2078.         }
  2079.     }
  2080.     
  2081.     if (document.readyState === 'loading') {
  2082.         document.addEventListener('DOMContentLoaded', initOnce);
  2083.     } else {
  2084.         // DOM is already ready
  2085.         initOnce();
  2086.     }
  2087.     
  2088.     // Also try with jQuery if available (for compatibility)
  2089.     if (typeof jQuery !== 'undefined') {
  2090.         jQuery(document).ready(function($) {
  2091.             console.log('jQuery ready, initializing...');
  2092.             initOnce();
  2093.         });
  2094.     }
  2095.     
  2096.     // Also scroll on window load (after all resources are loaded)
  2097.     {% if selectedTopic %}
  2098.     window.addEventListener('load', function() {
  2099.         setTimeout(function() {
  2100.             const kbContainer = document.getElementById('modern-kb-container');
  2101.             if (kbContainer) {
  2102.                 const containerRect = kbContainer.getBoundingClientRect();
  2103.                 const scrollY = window.scrollY || window.pageYOffset;
  2104.                 const containerTop = containerRect.top + scrollY;
  2105.                 
  2106.                 window.scrollTo({
  2107.                     top: Math.max(0, containerTop - 20),
  2108.                     behavior: 'smooth'
  2109.                 });
  2110.             }
  2111.         }, 200);
  2112.     });
  2113.     {% endif %}
  2114. })();
  2115. </script>
  2116. {% endblock %}