core-maugli 1.2.72 → 1.2.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "core-maugli",
3
3
  "description": "Astro & Tailwind CSS blog theme for Maugli.",
4
4
  "type": "module",
5
- "version": "1.2.72",
5
+ "version": "1.2.74",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile } from 'fs/promises';
4
+ import { dirname, join } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ async function testPWAConfig() {
11
+ try {
12
+ const configPath = join(__dirname, '..', 'astro.config.mjs');
13
+ const configContent = await readFile(configPath, 'utf-8');
14
+
15
+ console.log('🔍 Проверяем PWA конфигурацию в astro.config.mjs...\n');
16
+
17
+ // Проверяем наличие VitePWA
18
+ const hasVitePWA = configContent.includes('VitePWA');
19
+ const hasPWAImport = configContent.includes('vite-plugin-pwa');
20
+
21
+ console.log(`✅ VitePWA plugin: ${hasVitePWA ? '✅ Найден' : '❌ Не найден'}`);
22
+ console.log(`✅ vite-plugin-pwa import: ${hasPWAImport ? '✅ Найден' : '❌ Не найден'}`);
23
+
24
+ // Проверяем manifest
25
+ const hasManifest = configContent.includes('manifest');
26
+ console.log(`✅ Manifest config: ${hasManifest ? '✅ Найден' : '❌ Не найден'}`);
27
+
28
+ // Проверяем service worker (workbox config)
29
+ const hasWorkbox = configContent.includes('workbox');
30
+ console.log(`✅ Workbox config: ${hasWorkbox ? '✅ Найден' : '❌ Не найден'}`);
31
+
32
+ // Проверяем pwaOptions
33
+ const hasPWAOptions = configContent.includes('pwaOptions');
34
+ console.log(`✅ PWA Options: ${hasPWAOptions ? '✅ Найден' : '❌ Не найден'}`);
35
+
36
+ // Проверяем registerType
37
+ const hasRegisterType = configContent.includes('registerType');
38
+ console.log(`✅ Register Type: ${hasRegisterType ? '✅ Найден' : '❌ Не найден'}`);
39
+
40
+ if (hasVitePWA && hasPWAImport && hasManifest && hasWorkbox && hasPWAOptions) {
41
+ console.log('\n🚀 PWA конфигурация полная и готова к развертыванию!');
42
+ console.log('💡 Эта конфигурация будет принудительно обновлена в пользовательских блогах');
43
+ } else {
44
+ console.log('\n⚠️ PWA конфигурация неполная');
45
+ }
46
+
47
+ } catch (error) {
48
+ console.error('❌ Ошибка при проверке PWA:', error.message);
49
+ }
50
+ }
51
+
52
+ testPWAConfig();
@@ -10,11 +10,11 @@
10
10
  * node scripts/update-all-blogs.js /path/to/blogs/project1 /path/to/blogs/project2
11
11
  */
12
12
 
13
+ import { execSync } from 'child_process';
13
14
  import fs from 'fs';
14
15
  import path from 'path';
15
- import { execSync } from 'child_process';
16
16
 
17
- const CORE_MAUGLI_VERSION = '1.2.72';
17
+ const CORE_MAUGLI_VERSION = '1.2.74';
18
18
 
19
19
  // Correct scripts for package.json
20
20
  const CORRECT_SCRIPTS = {
@@ -0,0 +1,134 @@
1
+ ---
2
+ import { maugliConfig } from '../config/maugli.config';
3
+ import { LANGUAGES } from '../i18n/languages';
4
+
5
+ export interface FaqItem {
6
+ question: string;
7
+ answer: string;
8
+ }
9
+
10
+ export interface Props {
11
+ faq: FaqItem[];
12
+ }
13
+
14
+ const { faq } = Astro.props;
15
+ const lang = typeof maugliConfig.defaultLang === 'string' ? maugliConfig.defaultLang : 'en';
16
+ const languageObj = LANGUAGES.find((l) => l.code === lang) || LANGUAGES.find((l) => l.code === 'en');
17
+ const fallbackDict = LANGUAGES.find((l) => l.code === 'en')?.dict || {};
18
+ const dict = languageObj?.dict && Object.keys(languageObj.dict).length > 0 ? languageObj.dict : fallbackDict;
19
+ const faqCard = (dict as any).faqCard || (fallbackDict as any).faqCard || {};
20
+ ---
21
+
22
+ <section
23
+ class="w-full bg-[var(--bg-muted)] rounded-custom p-6 pl-8 sm:p-8 sm:pl-10 mt-8 mb-4 flex flex-col gap-6 sm:gap-10 overflow-hidden"
24
+ aria-label={faqCard.ariaLabel || 'Часто задаваемые вопросы'}
25
+ >
26
+ <div class="flex flex-col sm:flex-row gap-4 sm:gap-6">
27
+ <div class="flex-shrink-0">
28
+ <h3 class="font-serif text-[18px] font-bold flex items-center">
29
+ <span class="mr-2">
30
+ <svg width="20" height="20" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
31
+ <g clip-path="url(#clip0_3491_12505)">
32
+ <path
33
+ fill-rule="evenodd"
34
+ clip-rule="evenodd"
35
+ d="M12.5 0C19.4036 0 25 5.59644 25 12.5C25 19.4036 19.4036 25 12.5 25C5.59644 25 0 19.4036 0 12.5C0 5.59644 5.59644 0 12.5 0ZM12.7549 16.1074C12.5033 16.1075 12.2876 16.2001 12.1074 16.3857C11.9271 16.5715 11.8369 16.7943 11.8369 17.0537C11.837 17.313 11.9272 17.5359 12.1074 17.7217C12.2876 17.9072 12.5034 17.9999 12.7549 18C12.9248 18 13.0779 17.958 13.2139 17.874C13.3533 17.7864 13.4643 17.6701 13.5459 17.5264C13.6308 17.3828 13.6738 17.2253 13.6738 17.0537C13.6738 16.7944 13.5835 16.5715 13.4033 16.3857C13.2230 16.2 13.0066 16.1074 12.7549 16.1074ZM13.041 7C12.4901 7 11.9885 7.11263 11.5361 7.33691C11.0872 7.56126 10.7247 7.88541 10.4492 8.30957C10.1772 8.73371 10.0272 9.24397 10 9.83984H11.2861C11.3133 9.4262 11.4134 9.09086 11.5869 8.83496C11.7603 8.57924 11.976 8.39162 12.2344 8.27246C12.4929 8.15328 12.7621 8.09375 13.041 8.09375C13.3606 8.09378 13.6513 8.16218 13.9131 8.29883C14.175 8.43554 14.3846 8.63042 14.541 8.88281C14.6973 9.13512 14.7754 9.43301 14.7754 9.77637C14.7754 10.0532 14.728 10.3054 14.6328 10.5332C14.541 10.761 14.4147 10.9625 14.2549 11.1377C14.095 11.3095 13.9145 11.4588 13.7139 11.585C13.3806 11.7917 13.0955 12.0184 12.8574 12.2637C12.6193 12.509 12.4349 12.8295 12.3057 13.2256C12.1764 13.6217 12.1084 14.1547 12.1016 14.8242V14.8867H13.3262V14.8242C13.333 14.3895 13.3774 14.0263 13.459 13.7354C13.5406 13.4445 13.6714 13.1937 13.8516 12.9834C14.0318 12.7696 14.2721 12.5668 14.5713 12.374C14.8706 12.1847 15.126 11.9671 15.3369 11.7217C15.5511 11.4764 15.714 11.1976 15.8262 10.8857C15.9418 10.5739 16 10.2253 16 9.83984C16 9.29312 15.8776 8.80552 15.6328 8.37793C15.3913 7.95027 15.0471 7.61354 14.6016 7.36816C14.1595 7.12293 13.6394 7.00003 13.041 7Z"
36
+ fill="var(--brand-color)"></path>
37
+ </g>
38
+ <defs>
39
+ <clipPath id="clip0_3491_12505">
40
+ <rect width="25" height="25" fill="white"></rect>
41
+ </clipPath>
42
+ </defs>
43
+ </svg>
44
+ </span>
45
+ <span class="text-[var(--brand-color)]">{faqCard.faqLabel || 'FAQ:'}</span>
46
+ </h3>
47
+ </div>
48
+ <div class="flex-1 min-w-0 flex flex-col gap-2">
49
+ {
50
+ faq.map(({ question, answer }, index) => (
51
+ <div class="faq-item border-b border-[var(--border-color)] last:border-b-0">
52
+ <button
53
+ class="faq-toggle w-full text-left py-3 flex items-center justify-between group hover:bg-[var(--bg-card)] px-2 rounded transition-colors"
54
+ data-index={index}
55
+ aria-expanded={index === 0 ? "true" : "false"}
56
+ aria-controls={`faq-answer-${index}`}
57
+ >
58
+ <span class="font-sans text-[16px] text-[var(--text-heading)] flex-1 pr-4">
59
+ {question}
60
+ </span>
61
+ <span class="faq-chevron flex-shrink-0 transition-transform duration-200" style={index === 0 ? "transform: rotate(90deg)" : ""}>
62
+ <svg width="16" height="16" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
63
+ <g clip-path="url(#clip0_3491_12515)">
64
+ <path
65
+ fill-rule="evenodd"
66
+ clip-rule="evenodd"
67
+ d="M12.5 0C19.4036 0 25 5.59644 25 12.5C25 19.4036 19.4036 25 12.5 25C5.59644 25 0 19.4036 0 12.5C0 5.59644 5.59644 0 12.5 0ZM9.20801 8.80273L14.6641 12.499L9.8291 15.7764L9.20801 16.1963L10.0498 17.4385L16.4209 13.1201C16.6265 12.9806 16.7499 12.7485 16.75 12.5C16.75 12.2824 16.6556 12.0769 16.4941 11.9355L16.4209 11.8789L10.0498 7.56055L9.20801 8.80273Z"
68
+ fill="var(--brand-color)"
69
+ />
70
+ </g>
71
+ <defs>
72
+ <clipPath id="clip0_3491_12515">
73
+ <rect width="25" height="25" fill="white" />
74
+ </clipPath>
75
+ </defs>
76
+ </svg>
77
+ </span>
78
+ </button>
79
+ <div
80
+ class="faq-answer overflow-hidden transition-all duration-300 ease-in-out"
81
+ id={`faq-answer-${index}`}
82
+ style={index === 0 ? "max-height: 1000px; opacity: 1;" : "max-height: 0; opacity: 0;"}
83
+ >
84
+ <div class="font-sans text-[14px] text-[var(--text-main)] pb-4 px-2">
85
+ {answer}
86
+ </div>
87
+ </div>
88
+ </div>
89
+ ))
90
+ }
91
+ </div>
92
+ </div>
93
+ </section>
94
+
95
+ <script>
96
+ document.addEventListener('DOMContentLoaded', function() {
97
+ const faqToggles = document.querySelectorAll('.faq-toggle');
98
+
99
+ faqToggles.forEach(toggle => {
100
+ toggle.addEventListener('click', function() {
101
+ const index = this.dataset.index;
102
+ const answer = document.getElementById(`faq-answer-${index}`);
103
+ const chevron = this.querySelector('.faq-chevron');
104
+ const isExpanded = this.getAttribute('aria-expanded') === 'true';
105
+
106
+ // Закрываем все остальные
107
+ faqToggles.forEach((otherToggle, otherIndex) => {
108
+ if (otherToggle !== this) {
109
+ const otherAnswer = document.getElementById(`faq-answer-${otherIndex}`);
110
+ const otherChevron = otherToggle.querySelector('.faq-chevron');
111
+
112
+ otherToggle.setAttribute('aria-expanded', 'false');
113
+ otherAnswer.style.maxHeight = '0';
114
+ otherAnswer.style.opacity = '0';
115
+ otherChevron.style.transform = 'rotate(0deg)';
116
+ }
117
+ });
118
+
119
+ // Переключаем текущий
120
+ if (isExpanded) {
121
+ this.setAttribute('aria-expanded', 'false');
122
+ answer.style.maxHeight = '0';
123
+ answer.style.opacity = '0';
124
+ chevron.style.transform = 'rotate(0deg)';
125
+ } else {
126
+ this.setAttribute('aria-expanded', 'true');
127
+ answer.style.maxHeight = '1000px';
128
+ answer.style.opacity = '1';
129
+ chevron.style.transform = 'rotate(90deg)';
130
+ }
131
+ });
132
+ });
133
+ });
134
+ </script>
@@ -0,0 +1,51 @@
1
+ ---
2
+ import { maugliConfig } from '../config/maugli.config';
3
+ import { LANGUAGES } from '../i18n/languages';
4
+
5
+ export interface Props {
6
+ summary: string;
7
+ highlights: string[];
8
+ }
9
+
10
+ const { summary, highlights } = Astro.props;
11
+ const lang = typeof maugliConfig.defaultLang === 'string' ? maugliConfig.defaultLang : 'en';
12
+ const languageObj = LANGUAGES.find((l) => l.code === lang) || LANGUAGES.find((l) => l.code === 'en');
13
+ const fallbackDict = LANGUAGES.find((l) => l.code === 'en')?.dict || {};
14
+ const dict = languageObj?.dict && Object.keys(languageObj.dict).length > 0 ? languageObj.dict : fallbackDict;
15
+ const summaryCard = (dict as any).summaryCard || (fallbackDict as any).summaryCard || {};
16
+ ---
17
+
18
+ <section
19
+ class="w-full bg-[var(--bg-muted)] rounded-custom p-6 pl-8 sm:p-8 sm:pl-10 mt-0 mb-4 flex flex-col gap-6 sm:gap-10 overflow-hidden"
20
+ aria-label={summaryCard.ariaLabel || 'Саммари статьи'}
21
+ >
22
+ <div class="flex flex-col sm:flex-row gap-4 sm:gap-6">
23
+ <div class="flex-shrink-0">
24
+ <h3 class="font-serif text-[18px] font-bold flex items-center">
25
+ <span class="mr-2">
26
+ <svg width="20" height="20" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
27
+ <g clip-path="url(#clip0_3491_12503)">
28
+ <path
29
+ fill-rule="evenodd"
30
+ clip-rule="evenodd"
31
+ d="M12.5 0C9.18479 0 6.00537 1.31696 3.66117 3.66117C1.31696 6.00537 0 9.18479 0 12.5C0 15.8152 1.31696 18.9946 3.66117 21.3388C6.00537 23.683 9.18479 25 12.5 25C15.8152 25 18.9946 23.683 21.3388 21.3388C23.683 18.9946 25 15.8152 25 12.5C25 9.18479 23.683 6.00537 21.3388 3.66117C18.9946 1.31696 15.8152 0 12.5 0ZM8 9H9V10H8V9ZM10 9H18V10H10V9ZM8 11H9V12H8V11ZM10 11H15V12H10V11ZM8 13H9V14H8V13ZM10 13H17V14H10V13ZM8 15H9V16H8V15ZM10 15H19V16H10V15Z"
32
+ fill="var(--brand-color)"></path>
33
+ </g>
34
+ <defs>
35
+ <clipPath id="clip0_3491_12503">
36
+ <rect width="25" height="25" fill="white"></rect>
37
+ </clipPath>
38
+ </defs>
39
+ </svg>
40
+ </span>
41
+ <span class="text-[var(--brand-color)]">{summaryCard.summaryLabel || 'Саммари:'}</span>
42
+ </h3>
43
+ </div>
44
+ <div class="flex-1 min-w-0">
45
+ <div class="font-sans text-[16px] mb-4 text-[var(--text-main)] max-w-[calc(100%-2rem)]">{summary}</div>
46
+ <ul class="list-disc ml-6 font-sans text-[14px] text-[var(--text-heading)] leading-[1.2]">
47
+ {highlights.map((hl) => <li>{hl}</li>)}
48
+ </ul>
49
+ </div>
50
+ </div>
51
+ </section>
package/src/i18n/en.json CHANGED
@@ -88,6 +88,14 @@
88
88
  "yesterday": "yesterday"
89
89
  },
90
90
  "sidebarAriaLabel": "Sidebar",
91
+ "summaryCard": {
92
+ "ariaLabel": "Article Summary",
93
+ "summaryLabel": "Summary:"
94
+ },
95
+ "faqCard": {
96
+ "ariaLabel": "Frequently Asked Questions",
97
+ "faqLabel": "FAQ:"
98
+ },
91
99
  "summaryFAQCard": {
92
100
  "ariaLabel": "Summary and FAQ",
93
101
  "summaryLabel": "Summary:",
package/src/i18n/ru.json CHANGED
@@ -85,6 +85,14 @@
85
85
  "yesterday": "вчера"
86
86
  },
87
87
  "sidebarAriaLabel": "Сайдбар",
88
+ "summaryCard": {
89
+ "ariaLabel": "Саммари статьи",
90
+ "summaryLabel": "Саммари:"
91
+ },
92
+ "faqCard": {
93
+ "ariaLabel": "Часто задаваемые вопросы",
94
+ "faqLabel": "FAQ:"
95
+ },
88
96
  "summaryFAQCard": {
89
97
  "ariaLabel": "Саммари и FAQ",
90
98
  "summaryLabel": "Саммари:",
@@ -2,11 +2,12 @@
2
2
  import { type CollectionEntry, render } from 'astro:content';
3
3
  import ArticleMeta from '../../components/ArticleMeta.astro';
4
4
  import ContentFooter from '../../components/ContentFooter.astro';
5
+ import FAQCard from '../../components/FAQCard.astro';
5
6
  import HeroImage from '../../components/HeroImage.astro';
6
7
  import PostPreview from '../../components/PostPreview.astro';
7
8
  import ProductBannerCard from '../../components/ProductBannerCard.astro';
8
9
  import Subscribe from '../../components/Subscribe.astro';
9
- import SummaryFAQCard from '../../components/SummaryFAQCard.astro';
10
+ import SummaryCard from '../../components/SummaryCard.astro';
10
11
  import TableOfContents from '../../components/TableOfContents.astro';
11
12
  import TagsAndShare from '../../components/TagsAndShare.astro';
12
13
  import { maugliConfig } from '../../config/maugli.config';
@@ -131,17 +132,15 @@ if (post.data.productID) {
131
132
 
132
133
  <!-- Основной контент -->
133
134
  <div class="md:col-span-11 px-4 md:px-0 h-auto lg:col-span-11">
134
- <!-- Summary/FAQ в начале контента -->
135
+ <!-- Summary в начале контента -->
135
136
  {
136
137
  post.data.generativeEngineOptimization?.generated &&
137
138
  (post.data.generativeEngineOptimization.generated.summary ||
138
- post.data.generativeEngineOptimization.generated.highlights?.length > 0 ||
139
- post.data.generativeEngineOptimization.generated.faq?.length > 0) && (
139
+ post.data.generativeEngineOptimization.generated.highlights?.length > 0) && (
140
140
  <div class="not-prose mb-8">
141
- <SummaryFAQCard
141
+ <SummaryCard
142
142
  summary={post.data.generativeEngineOptimization.generated.summary}
143
143
  highlights={post.data.generativeEngineOptimization.generated.highlights}
144
- faq={post.data.generativeEngineOptimization.generated.faq}
145
144
  />
146
145
  </div>
147
146
  )
@@ -155,6 +154,16 @@ if (post.data.productID) {
155
154
  <!-- Блок тегов и кнопки поделиться под контентом (только на мобилке) -->
156
155
  <ContentFooter tags={tags} shareUrl={href} title={title} basePath="/blog" productLink={post.data.productLink} />
157
156
 
157
+ <!-- FAQ после контента -->
158
+ {
159
+ post.data.generativeEngineOptimization?.generated?.faq &&
160
+ post.data.generativeEngineOptimization.generated.faq.length > 0 && (
161
+ <div class="not-prose mb-8">
162
+ <FAQCard faq={post.data.generativeEngineOptimization.generated.faq} />
163
+ </div>
164
+ )
165
+ }
166
+
158
167
  {
159
168
  (prevPost || nextPost) && (
160
169
  <div class="my-16 sm:my-24">
@@ -4,10 +4,11 @@ import { getFilteredCollection } from '../../utils/content-loader';
4
4
  import ArticleMeta from '../../components/ArticleMeta.astro';
5
5
  import Breadcrumbs from '../../components/Breadcrumbs.astro';
6
6
  import ContentFooter from '../../components/ContentFooter.astro';
7
+ import FAQCard from '../../components/FAQCard.astro';
7
8
  import HeroImage from '../../components/HeroImage.astro';
8
9
  import PostPreview from '../../components/PostPreview.astro';
9
10
  import ProjectPreview from '../../components/ProjectPreview.astro';
10
- import SummaryFAQCard from '../../components/SummaryFAQCard.astro';
11
+ import SummaryCard from '../../components/SummaryCard.astro';
11
12
  import TableOfContents from '../../components/TableOfContents.astro';
12
13
  import TagsAndShare from '../../components/TagsAndShare.astro';
13
14
  import { maugliConfig } from '../../config/maugli.config';
@@ -98,17 +99,15 @@ const moreLabel = dict.buttons?.more || dicts['en'].buttons.more || 'More';
98
99
  </div>
99
100
  </aside>
100
101
  <div class="md:col-span-11 px-4 md:px-0 h-auto lg:col-span-11">
101
- {/* Summary/FAQ для продукта */}
102
+ {/* Summary для продукта */}
102
103
  {
103
104
  product.data.generativeEngineOptimization?.generated &&
104
105
  (product.data.generativeEngineOptimization.generated.summary ||
105
- product.data.generativeEngineOptimization.generated.highlights?.length > 0 ||
106
- product.data.generativeEngineOptimization.generated.faq?.length > 0) && (
106
+ product.data.generativeEngineOptimization.generated.highlights?.length > 0) && (
107
107
  <div class="not-prose mb-8">
108
- <SummaryFAQCard
108
+ <SummaryCard
109
109
  summary={product.data.generativeEngineOptimization.generated.summary}
110
110
  highlights={product.data.generativeEngineOptimization.generated.highlights}
111
- faq={product.data.generativeEngineOptimization.generated.faq}
112
111
  />
113
112
  </div>
114
113
  )
@@ -116,6 +115,17 @@ const moreLabel = dict.buttons?.more || dicts['en'].buttons.more || 'More';
116
115
  <div class="prose sm:prose-lg lg:prose-xl max-w-none">
117
116
  <Content />
118
117
  </div>
118
+
119
+ {/* FAQ после контента продукта */}
120
+ {
121
+ product.data.generativeEngineOptimization?.generated?.faq &&
122
+ product.data.generativeEngineOptimization.generated.faq.length > 0 && (
123
+ <div class="not-prose mb-8">
124
+ <FAQCard faq={product.data.generativeEngineOptimization.generated.faq} />
125
+ </div>
126
+ )
127
+ }
128
+
119
129
  <ContentFooter tags={tags} shareUrl={href} title={title} basePath="/products" />
120
130
  {/* Связанные статьи */}
121
131
  {
@@ -3,10 +3,11 @@ import { getCollection, render, type CollectionEntry } from 'astro:content';
3
3
  import ArticleMeta from '../../components/ArticleMeta.astro';
4
4
  import Breadcrumbs from '../../components/Breadcrumbs.astro';
5
5
  import ContentFooter from '../../components/ContentFooter.astro';
6
+ import FAQCard from '../../components/FAQCard.astro';
6
7
  import HeroImage from '../../components/HeroImage.astro';
7
8
  import ProductBannerCard from '../../components/ProductBannerCard.astro';
8
9
  import ProjectPreview from '../../components/ProjectPreview.astro';
9
- import SummaryFAQCard from '../../components/SummaryFAQCard.astro';
10
+ import SummaryCard from '../../components/SummaryCard.astro';
10
11
  import TableOfContents from '../../components/TableOfContents.astro';
11
12
  import TagsAndShare from '../../components/TagsAndShare.astro';
12
13
  import { maugliConfig } from '../../config/maugli.config';
@@ -119,17 +120,15 @@ const moreByTag = pages.projects?.moreByTag || 'More cases';
119
120
 
120
121
  <!-- Основной контент -->
121
122
  <div class="md:col-span-11 px-4 md:px-0 h-auto lg:col-span-11">
122
- <!-- Summary/FAQ в начале контента -->
123
+ <!-- Summary в начале контента -->
123
124
  {
124
125
  project.data.generativeEngineOptimization?.generated &&
125
126
  (project.data.generativeEngineOptimization.generated.summary ||
126
- project.data.generativeEngineOptimization.generated.highlights?.length > 0 ||
127
- project.data.generativeEngineOptimization.generated.faq?.length > 0) && (
127
+ project.data.generativeEngineOptimization.generated.highlights?.length > 0) && (
128
128
  <div class="not-prose mb-8">
129
- <SummaryFAQCard
129
+ <SummaryCard
130
130
  summary={project.data.generativeEngineOptimization.generated.summary}
131
131
  highlights={project.data.generativeEngineOptimization.generated.highlights}
132
- faq={project.data.generativeEngineOptimization.generated.faq}
133
132
  />
134
133
  </div>
135
134
  )
@@ -145,6 +144,16 @@ const moreByTag = pages.projects?.moreByTag || 'More cases';
145
144
  {/* Мобильный блок: поделиться и "Больше о продукте" в один ряд */}
146
145
  <ContentFooter tags={tags} shareUrl={href} title={title} basePath="/projects" class="sm:hidden" productLink={project.data.productLink} />
147
146
 
147
+ <!-- FAQ после контента -->
148
+ {
149
+ project.data.generativeEngineOptimization?.generated?.faq &&
150
+ project.data.generativeEngineOptimization.generated.faq.length > 0 && (
151
+ <div class="not-prose mb-8">
152
+ <FAQCard faq={project.data.generativeEngineOptimization.generated.faq} />
153
+ </div>
154
+ )
155
+ }
156
+
148
157
  <!-- Блок "Еще по теме" в контенте -->
149
158
  {
150
159
  (prevProject || nextProject) && (