core-maugli 1.2.20 → 1.2.22
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
@@ -1,7 +1,9 @@
|
|
1
1
|
---
|
2
|
-
import {
|
3
|
-
import siteConfig from '../data/site-config.ts';
|
2
|
+
import type { CollectionEntry } from 'astro:content';
|
4
3
|
import '../styles/global.css';
|
4
|
+
import { getFilteredCollection } from '../utils/content-loader';
|
5
|
+
import siteConfig from '../data/site-config';
|
6
|
+
import { getAbsoluteLocaleUrl, getRelativeLocaleUrl } from 'astro:i18n';
|
5
7
|
// Определи тип выше:
|
6
8
|
export type ImageMimeType = 'image/jpeg' | 'image/png' | 'image/webp';
|
7
9
|
|
@@ -86,6 +88,72 @@ let defaultAuthorName = defaultAuthor.data.name;
|
|
86
88
|
<meta name="robots" content="index, follow" />
|
87
89
|
<meta name="generator" content={Astro.generator} />
|
88
90
|
|
91
|
+
<!-- Critical CSS Inline for Performance -->
|
92
|
+
<style>
|
93
|
+
:root {
|
94
|
+
--brand-color-rgb: 12, 191, 17;
|
95
|
+
--brand-color: rgb(var(--brand-color-rgb));
|
96
|
+
--text-main: #111c2d;
|
97
|
+
--text-heading: #3b5174;
|
98
|
+
--text-muted: #6b7280;
|
99
|
+
--bg-main: #ffffff;
|
100
|
+
--bg-muted: rgba(237, 241, 247, 0.621);
|
101
|
+
--border-main: rgba(17, 28, 44, 0.13);
|
102
|
+
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
103
|
+
--font-serif: 'Geologica', Georgia, 'Times New Roman', serif;
|
104
|
+
}
|
105
|
+
html.dark {
|
106
|
+
--brand-color-rgb: 13, 211, 18;
|
107
|
+
--brand-color: rgb(var(--brand-color-rgb));
|
108
|
+
--text-main: #ffffff;
|
109
|
+
--text-heading: rgba(202, 252, 254, 0.7);
|
110
|
+
--text-muted: #9ca3af;
|
111
|
+
--bg-main: #0b131e;
|
112
|
+
--bg-muted: #131d2cde;
|
113
|
+
--border-main: rgba(51, 66, 66, 0.6);
|
114
|
+
}
|
115
|
+
body {
|
116
|
+
font-family: var(--font-sans);
|
117
|
+
color: var(--text-main);
|
118
|
+
background-color: var(--bg-main);
|
119
|
+
margin: 0;
|
120
|
+
line-height: 1.5;
|
121
|
+
}
|
122
|
+
* {
|
123
|
+
box-sizing: border-box;
|
124
|
+
}
|
125
|
+
</style>
|
126
|
+
|
127
|
+
<!-- Critical Resource Preloading for Performance -->
|
128
|
+
<link rel="preload" href="/favicon.svg" as="image" type="image/svg+xml" />
|
129
|
+
<link rel="preload" href="/footerlabel.svg" as="image" type="image/svg+xml" />
|
130
|
+
<link rel="dns-prefetch" href="https://fonts.googleapis.com" />
|
131
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin />
|
132
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
133
|
+
|
134
|
+
<!-- Image Optimization Hints -->
|
135
|
+
<meta name="format-detection" content="telephone=no" />
|
136
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
|
137
|
+
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
138
|
+
|
139
|
+
<!-- Font Loading Strategy - Non-blocking -->
|
140
|
+
<link
|
141
|
+
rel="preload"
|
142
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
|
143
|
+
as="style"
|
144
|
+
onload="this.onload=null;this.rel='stylesheet'"
|
145
|
+
/>
|
146
|
+
<link
|
147
|
+
rel="preload"
|
148
|
+
href="https://fonts.googleapis.com/css2?family=Geologica:wght@400;500;600&display=swap"
|
149
|
+
as="style"
|
150
|
+
onload="this.onload=null;this.rel='stylesheet'"
|
151
|
+
/>
|
152
|
+
<noscript>
|
153
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" />
|
154
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geologica:wght@400;500;600&display=swap" />
|
155
|
+
</noscript>
|
156
|
+
|
89
157
|
<!-- SEO -->
|
90
158
|
<meta name="description" content={seoDescription} />
|
91
159
|
<meta name="keywords" content={seoKeywords} />
|
@@ -108,8 +176,8 @@ let defaultAuthorName = defaultAuthor.data.name;
|
|
108
176
|
<meta property="og:description" content={seoDescription} />
|
109
177
|
{resolvedImage?.src && <meta property="og:image" content={resolvedImage.src} />}
|
110
178
|
{resolvedImage?.alt && <meta property="og:image:alt" content={resolvedImage.alt} />}
|
111
|
-
{typeof resolvedImage?.width !== 'undefined' && <meta property="og:image:width" content={resolvedImage.width} />}
|
112
|
-
{typeof resolvedImage?.height !== 'undefined' && <meta property="og:image:height" content={resolvedImage.height} />}
|
179
|
+
{typeof resolvedImage?.width !== 'undefined' && <meta property="og:image:width" content={resolvedImage.width.toString()} />}
|
180
|
+
{typeof resolvedImage?.height !== 'undefined' && <meta property="og:image:height" content={resolvedImage.height.toString()} />}
|
113
181
|
{resolvedImage?.type && <meta property="og:image:type" content={resolvedImage.type} />}
|
114
182
|
|
115
183
|
<!-- X/Twitter -->
|
@@ -2,6 +2,7 @@
|
|
2
2
|
import { maugliConfig } from '../config/maugli.config';
|
3
3
|
import { LANGUAGES } from '../i18n/languages';
|
4
4
|
import AuthorLinksGroup from './AuthorLinksGroup.astro';
|
5
|
+
import OptimizedImage from './OptimizedImage.astro';
|
5
6
|
// Универсальный импорт словарей по доступным языкам
|
6
7
|
const dicts: Record<string, any> = {};
|
7
8
|
for (const lang of LANGUAGES) {
|
@@ -9,7 +10,7 @@ for (const lang of LANGUAGES) {
|
|
9
10
|
dicts[lang.code] = await import(`../i18n/${lang.code}.json`).then((m) => m.default);
|
10
11
|
} catch {}
|
11
12
|
}
|
12
|
-
const lang = maugliConfig.
|
13
|
+
const lang = maugliConfig.defaultLang || 'en';
|
13
14
|
const dict = dicts[lang] || dicts['en'] || {};
|
14
15
|
|
15
16
|
const navLinks = (maugliConfig.navLinks || []).map((link) => ({
|
@@ -109,7 +110,18 @@ const copyrightYears = yearStart === yearEnd ? `${yearStart}` : `${yearStart}–
|
|
109
110
|
]}
|
110
111
|
>
|
111
112
|
<div class="flex flex-row justify-between items-end w-full mt-2">
|
112
|
-
<
|
113
|
+
<div class="flex flex-col items-start gap-1">
|
114
|
+
<img src="/footerlabel.svg" alt="Maugli Label" style="height:32px;width:auto;" loading="lazy" decoding="async" />
|
115
|
+
<a
|
116
|
+
href="https://www.npmjs.com/package/core-maugli"
|
117
|
+
target="_blank"
|
118
|
+
rel="noopener noreferrer"
|
119
|
+
class="footer-link text-xs opacity-60 hover:opacity-100"
|
120
|
+
style="color:var(--text-muted);font-family:var(--font-sans);"
|
121
|
+
>
|
122
|
+
npm package
|
123
|
+
</a>
|
124
|
+
</div>
|
113
125
|
{
|
114
126
|
Object.values(maugliConfig.links || {}).some(Boolean) && (
|
115
127
|
<div class="flex flex-row items-center gap-2 ml-4">
|
@@ -0,0 +1,67 @@
|
|
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
|
+
priority?: boolean;
|
12
|
+
quality?: number;
|
13
|
+
}
|
14
|
+
|
15
|
+
const {
|
16
|
+
src,
|
17
|
+
alt,
|
18
|
+
width,
|
19
|
+
height,
|
20
|
+
class: className = '',
|
21
|
+
loading = 'lazy',
|
22
|
+
decoding = 'async',
|
23
|
+
sizes,
|
24
|
+
priority = false,
|
25
|
+
quality = 75,
|
26
|
+
...rest
|
27
|
+
} = Astro.props;
|
28
|
+
|
29
|
+
// Generate responsive image variations with quality optimization
|
30
|
+
const generateSrcSet = (baseSrc: string) => {
|
31
|
+
const baseUrl = baseSrc.replace(/\.[^.]+$/, '');
|
32
|
+
const ext = 'webp'; // Always use WebP for better compression
|
33
|
+
|
34
|
+
const variations = [
|
35
|
+
{ width: 400, suffix: '-400' },
|
36
|
+
{ width: 800, suffix: '-800' },
|
37
|
+
{ width: 1200, suffix: '-1200' }
|
38
|
+
];
|
39
|
+
|
40
|
+
return variations
|
41
|
+
.map(({ width, suffix }) => `${baseUrl}${suffix}.${ext} ${width}w`)
|
42
|
+
.join(', ');
|
43
|
+
};
|
44
|
+
|
45
|
+
const srcSet = generateSrcSet(src);
|
46
|
+
const defaultSizes = sizes || '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw';
|
47
|
+
|
48
|
+
// For priority images, we'll preload them
|
49
|
+
const shouldPreload = priority && loading === 'eager';
|
50
|
+
---
|
51
|
+
|
52
|
+
<img
|
53
|
+
src={src}
|
54
|
+
srcset={srcSet}
|
55
|
+
sizes={defaultSizes}
|
56
|
+
alt={alt}
|
57
|
+
width={width}
|
58
|
+
height={height}
|
59
|
+
class={className}
|
60
|
+
loading={priority ? 'eager' : loading}
|
61
|
+
decoding={decoding}
|
62
|
+
{...rest}
|
63
|
+
/>
|
64
|
+
|
65
|
+
{priority && (
|
66
|
+
<link rel="preload" as="image" href={src} type="image/webp" />
|
67
|
+
)}
|