core-maugli 1.2.22 → 1.2.23

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.22",
5
+ "version": "1.2.23",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
@@ -1,9 +1,7 @@
1
1
  ---
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
2
  import { maugliConfig } from '../config/maugli.config';
6
3
  import FormattedDate from './FormattedDate.astro';
4
+ import ResponsiveImage from './ResponsiveImage.astro';
7
5
 
8
6
  type Props = {
9
7
  href: string;
@@ -16,7 +14,7 @@ type Props = {
16
14
  headingLevel?: 'h2' | 'h3';
17
15
  isFeatured?: boolean;
18
16
  class?: string;
19
- type?: string; // добавлен тип
17
+ type?: string;
20
18
  };
21
19
 
22
20
  const { href, title, image, seo, publishDate, excerpt, description, headingLevel = 'h2', isFeatured = false, class: className, type } = Astro.props;
@@ -35,62 +33,8 @@ const baseImage =
35
33
  ? maugliConfig.defaultProductImage
36
34
  : maugliConfig.seo.defaultImage);
37
35
 
38
- // Генерируем адаптивные версии изображений
39
- function getResponsiveImages(imagePath: string) {
40
- const basePath = imagePath.replace(/\.(webp|jpg|jpeg|png)$/i, '');
41
- const extension = imagePath.match(/\.(webp|jpg|jpeg|png)$/i)?.[0] || '.webp';
42
-
43
- // Проверяем существование адаптивных версий
44
- const __filename = fileURLToPath(import.meta.url);
45
- const projectRoot = path.resolve(path.dirname(__filename), '../..');
46
-
47
- const variants = [
48
- { suffix: '-400', width: '400w' },
49
- { suffix: '-800', width: '800w' },
50
- { suffix: '-1200', width: '1200w' }
51
- ];
52
-
53
- const srcsetItems = [];
54
-
55
- // Добавляем адаптивные версии, если они существуют
56
- for (const variant of variants) {
57
- const variantPath = `${basePath}${variant.suffix}${extension}`;
58
- const filePath = path.join(projectRoot, 'public', variantPath.replace(/^\//, ''));
59
-
60
- if (fs.existsSync(filePath)) {
61
- srcsetItems.push(`${variantPath} ${variant.width}`);
62
- }
63
- }
64
-
65
- // Всегда добавляем оригинальное изображение
66
- srcsetItems.push(`${imagePath} 1200w`);
67
-
68
- return {
69
- src: imagePath,
70
- srcset: srcsetItems.join(', '),
71
- sizes: '(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 400px'
72
- };
73
- }
74
-
75
- const cardImage = getResponsiveImages(baseImage);
76
36
  const cardImageAlt = seo?.image?.alt || image?.alt || title || 'Изображение';
77
37
 
78
- // Используем уменьшенное превью, если оно существует
79
- let previewImage;
80
- if (cardImage.src) {
81
- previewImage = cardImage.src.replace(/\/([^\/]+)$/, '/previews/$1');
82
-
83
- const __filename = fileURLToPath(import.meta.url);
84
- const projectRoot = path.resolve(path.dirname(__filename), '../..');
85
- const previewFilePath = path.join(projectRoot, 'public', previewImage.replace(/^\//, ''));
86
-
87
- if (!fs.existsSync(previewFilePath)) {
88
- previewImage = undefined;
89
- }
90
- }
91
-
92
- const finalImage = previewImage || cardImage.src;
93
-
94
38
  // Определяем контент для отображения
95
39
  const content = excerpt || description;
96
40
  ---
@@ -105,15 +49,16 @@ const content = excerpt || description;
105
49
  <a href={href} class="block w-full h-full">
106
50
  <!-- Изображение -->
107
51
  <div class="w-full aspect-[1200/630] bg-[var(--bg-muted)] overflow-hidden relative">
108
- <img
109
- src={finalImage}
110
- srcset={cardImage.srcset}
111
- sizes={cardImage.sizes}
52
+ <ResponsiveImage
53
+ src={baseImage}
112
54
  alt={cardImageAlt}
55
+ width={1200}
56
+ height={630}
113
57
  loading="lazy"
114
- width="1200"
115
- height="630"
116
58
  class="w-full h-full object-cover rounded-custom transition-transform duration-300 group-hover:scale-105"
59
+ sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 400px"
60
+ quality={75}
61
+ format="webp"
117
62
  />
118
63
 
119
64
  <!-- Звездочка featured в правом верхнем углу -->
@@ -0,0 +1,84 @@
1
+ ---
2
+ export interface Props {
3
+ src: string;
4
+ alt: string;
5
+ width?: number;
6
+ height?: number;
7
+ class?: string;
8
+ loading?: 'lazy' | 'eager';
9
+ decoding?: 'async' | 'sync' | 'auto';
10
+ sizes?: string;
11
+ quality?: number;
12
+ format?: 'webp' | 'avif' | 'jpeg' | 'png';
13
+ }
14
+
15
+ const {
16
+ src,
17
+ alt,
18
+ width = 1200,
19
+ height = 630,
20
+ class: className = '',
21
+ loading = 'lazy',
22
+ decoding = 'async',
23
+ sizes = '(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 400px',
24
+ quality = 75,
25
+ format = 'webp',
26
+ ...rest
27
+ } = Astro.props;
28
+
29
+ // Генерируем оптимизированные URL для разных размеров
30
+ const generateImageURL = (baseSrc: string, width: number, quality: number, format: string) => {
31
+ // Если это внешний URL, возвращаем как есть
32
+ if (baseSrc.startsWith('http')) {
33
+ return baseSrc;
34
+ }
35
+
36
+ // Для карточек проверяем наличие preview версии
37
+ const previewSrc = baseSrc.replace(/\/([^\/]+)$/, '/previews/$1');
38
+
39
+ // Возвращаем базовое изображение (preview будет проверен в build time)
40
+ return baseSrc;
41
+ };
42
+
43
+ const optimizedSrc = generateImageURL(src, width, quality, format);
44
+
45
+ // Генерируем srcset для адаптивности (используем готовые варианты)
46
+ const generateSrcSet = (baseSrc: string) => {
47
+ if (baseSrc.startsWith('http')) {
48
+ return baseSrc;
49
+ }
50
+
51
+ const baseUrl = baseSrc.replace(/\.[^.]+$/, '');
52
+ const ext = '.webp';
53
+
54
+ // Используем существующие responsive варианты
55
+ const variants = [
56
+ { width: 400, suffix: '-400' },
57
+ { width: 800, suffix: '-800' },
58
+ { width: 1200, suffix: '-1200' }
59
+ ];
60
+
61
+ const srcsetItems = variants
62
+ .map(({ width, suffix }) => `${baseUrl}${suffix}${ext} ${width}w`);
63
+
64
+ // Добавляем оригинал как fallback
65
+ srcsetItems.push(`${baseSrc} 1200w`);
66
+
67
+ return srcsetItems.join(', ');
68
+ };
69
+
70
+ const srcSet = generateSrcSet(src);
71
+ ---
72
+
73
+ <img
74
+ src={optimizedSrc}
75
+ srcset={srcSet}
76
+ alt={alt}
77
+ width={width}
78
+ height={height}
79
+ class={className}
80
+ loading={loading}
81
+ decoding={decoding}
82
+ sizes={sizes}
83
+ {...rest}
84
+ />