core-maugli 1.0.2
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/LICENSE +727 -0
- package/README.md +108 -0
- package/bin/index.js +9 -0
- package/bin/init.js +38 -0
- package/package.json +73 -0
- package/public/blackbox.webp +0 -0
- package/public/favicon.svg +10 -0
- package/public/footerlabel.svg +18 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/img/page-images/blog_default.webp +0 -0
- package/public/logo-icon.svg +3 -0
- package/public/logoblog-icon.svg +10 -0
- package/public/manifest.webmanifest +21 -0
- package/public/maugli_for_animation.svg +6 -0
- package/public/mauglilabel.svg +17 -0
- package/public/tr-about-1200.webp +0 -0
- package/public/tr-about-400.webp +0 -0
- package/public/tr-about-800.webp +0 -0
- package/public/tr-about.webp +0 -0
- package/public/tr-post-1-1200.webp +0 -0
- package/public/tr-post-1-400.webp +0 -0
- package/public/tr-post-1-800.webp +0 -0
- package/public/tr-post0-1200.webp +0 -0
- package/public/tr-post0-400.webp +0 -0
- package/public/tr-post0-800.webp +0 -0
- package/public/tr-post0.webp +0 -0
- package/public/tr-prewiew.webp +0 -0
- package/resize-all.cjs +29 -0
- package/scripts/featured.js +208 -0
- package/scripts/update-with-backup.js +34 -0
- package/scripts/upgrade-config.js +90 -0
- package/scripts/verify-assets.js +28 -0
- package/src/assets/img/default/autor_default.webp +0 -0
- package/src/assets/img/default/blog_default.webp +0 -0
- package/src/assets/img/default/product_default.webp +0 -0
- package/src/assets/img/default/project_default.webp +0 -0
- package/src/assets/img/default/rubric_default.webp +0 -0
- package/src/assets/img/examples/authors/anna.webp +0 -0
- package/src/assets/img/examples/authors/carlos.webp +0 -0
- package/src/assets/img/examples/authors/daria.webp +0 -0
- package/src/assets/img/examples/authors/dmitry.webp +0 -0
- package/src/assets/img/examples/authors/igor.webp +0 -0
- package/src/assets/img/examples/authors/john.webp +0 -0
- package/src/assets/img/examples/blog/post-1-avtomatizaciya-marketinga-kak-ii-osvobozhdaet-predprinimatelei-ot-cifrovogo-rabstva.webp +0 -0
- package/src/assets/img/examples/blog/post_11.webp +0 -0
- package/src/assets/img/examples/blog/post_12.webp +0 -0
- package/src/assets/img/examples/blog/post_1_jsonld_guide.webp +0 -0
- package/src/assets/img/examples/blog/test-post.webp +0 -0
- package/src/assets/img/examples/blog/tr-post-1.webp +0 -0
- package/src/assets/img/examples/products/product_1.webp +0 -0
- package/src/assets/img/examples/products/product_2.webp +0 -0
- package/src/assets/img/examples/projects/project_1.webp +0 -0
- package/src/assets/img/examples/projects/project_2.webp +0 -0
- package/src/components/ArticleMeta.astro +103 -0
- package/src/components/AuthorCard.astro +95 -0
- package/src/components/AuthorLink.astro +25 -0
- package/src/components/AuthorLinksGroup.astro +135 -0
- package/src/components/Avatar.astro +32 -0
- package/src/components/BaseHead.astro +121 -0
- package/src/components/Breadcrumbs.astro +90 -0
- package/src/components/Button.astro +25 -0
- package/src/components/Card.astro +99 -0
- package/src/components/ContentFooter.astro +147 -0
- package/src/components/CopyLinkButton.astro +133 -0
- package/src/components/CountBadge.astro +17 -0
- package/src/components/Footer.astro +122 -0
- package/src/components/FormattedDate.astro +59 -0
- package/src/components/Header.astro +18 -0
- package/src/components/HeroImage.astro +38 -0
- package/src/components/IconButton.astro +23 -0
- package/src/components/Image.astro +13 -0
- package/src/components/InfoCard.astro +123 -0
- package/src/components/LanguageSwitcher.astro +122 -0
- package/src/components/MaugliFloatingLabel.astro +454 -0
- package/src/components/MobileTagsAndShare.astro +71 -0
- package/src/components/Nav.astro +151 -0
- package/src/components/NavLink.astro +31 -0
- package/src/components/Pagination.astro +70 -0
- package/src/components/PostPreview.astro +22 -0
- package/src/components/ProductBannerCard.astro +47 -0
- package/src/components/ProductPreview.astro +21 -0
- package/src/components/ProjectPreview.astro +21 -0
- package/src/components/RubricCard.astro +142 -0
- package/src/components/ShareIcon.astro +93 -0
- package/src/components/ShareLink.astro +58 -0
- package/src/components/Subscribe.astro +68 -0
- package/src/components/SummaryFAQCard.astro +106 -0
- package/src/components/TableOfContents.astro +143 -0
- package/src/components/TagPill.astro +41 -0
- package/src/components/TagPills.astro +42 -0
- package/src/components/TagsAndShare.astro +379 -0
- package/src/components/TagsSection.astro +203 -0
- package/src/components/ThemeToggle.astro +58 -0
- package/src/config/maugli.config.ts +213 -0
- package/src/content/authors/daria-zorina.md +42 -0
- package/src/content/authors/default-autor.md +47 -0
- package/src/content/authors/igor-sokolov.md +43 -0
- package/src/content/authors/john-walker.md +46 -0
- package/src/content/blog/jsonld-guide.md +260 -0
- package/src/content/blog/post-0.md +49 -0
- package/src/content/blog/post-1-avtomatizaciya-marketinga-kak-ii-osvobozhdaet-predprinimatelei-ot-cifrovogo-rabstva.md +72 -0
- package/src/content/blog/post-agent-experience-mcp-biznes-v-epohu-ii-agentov.md +116 -0
- package/src/content/blog/test-post-2025-07-11.md +73 -0
- package/src/content/config.ts +80 -0
- package/src/content/pages/about.md +40 -0
- package/src/content/pages/about.mdx +27 -0
- package/src/content/pages/authors.mdx +49 -0
- package/src/content/pages/blog.mdx +31 -0
- package/src/content/pages/contact.md +10 -0
- package/src/content/pages/products.mdx +30 -0
- package/src/content/pages/projects.mdx +28 -0
- package/src/content/pages/rubrics.mdx +35 -0
- package/src/content/pages/terms.md +12 -0
- package/src/content/products/example-product.md +28 -0
- package/src/content/products/maugli-editor.md +35 -0
- package/src/content/products/maugli-freeblog.md +162 -0
- package/src/content/projects/example-project.md +28 -0
- package/src/content/projects/project-1.md +70 -0
- package/src/content/projects/project-2.md +33 -0
- package/src/content/tags/ai-business.mdx +18 -0
- package/src/content/tags/automation.mdx +18 -0
- package/src/content/tags/content-strategy.mdx +18 -0
- package/src/content/tags/growth-marketing.mdx +18 -0
- package/src/content/tags/industry-reviews.mdx +18 -0
- package/src/content/tags/interesting.mdx +18 -0
- package/src/content/tags/seo-ai-seo.mdx +18 -0
- package/src/content.config.ts +260 -0
- package/src/data/site-config.ts +164 -0
- package/src/i18n/de.json +126 -0
- package/src/i18n/en.json +126 -0
- package/src/i18n/es.json +126 -0
- package/src/i18n/fr.json +126 -0
- package/src/i18n/index.ts +10 -0
- package/src/i18n/ja.json +126 -0
- package/src/i18n/languages.ts +23 -0
- package/src/i18n/pt.json +126 -0
- package/src/i18n/ru.json +123 -0
- package/src/i18n/zh.json +126 -0
- package/src/icons/ArrowLeft.astro +13 -0
- package/src/icons/ArrowRight.astro +13 -0
- package/src/icons/flags/brazil.svg +14 -0
- package/src/icons/flags/china.svg +15 -0
- package/src/icons/flags/france.svg +12 -0
- package/src/icons/flags/germany.svg +12 -0
- package/src/icons/flags/japan.svg +11 -0
- package/src/icons/flags/russia.svg +12 -0
- package/src/icons/flags/spain.svg +12 -0
- package/src/icons/flags/united arab emirates.svg +13 -0
- package/src/icons/flags/united states.svg +15 -0
- package/src/icons/socials/BlueskyIcon.astro +9 -0
- package/src/icons/socials/EmailIcon.astro +8 -0
- package/src/icons/socials/LinkedinIcon.astro +9 -0
- package/src/icons/socials/MastodonIcon.astro +9 -0
- package/src/icons/socials/MediumIcon.astro +9 -0
- package/src/icons/socials/RedditIcon.astro +11 -0
- package/src/icons/socials/TelegramIcon.astro +11 -0
- package/src/icons/socials/TwitterIcon.astro +9 -0
- package/src/img/default/autor_default.webp +0 -0
- package/src/img/default/default.webp +0 -0
- package/src/img/default/rubric_default.webp +0 -0
- package/src/img/default/test.webp +0 -0
- package/src/img/default/test2.webp +0 -0
- package/src/img/examples/authors/anna.webp +0 -0
- package/src/img/examples/authors/carlos.webp +0 -0
- package/src/img/examples/authors/daria.webp +0 -0
- package/src/img/examples/authors/dmitry.webp +0 -0
- package/src/img/examples/authors/igor.webp +0 -0
- package/src/img/examples/authors/john.webp +0 -0
- package/src/img/examples/blog/post-1-avtomatizaciya-marketinga-kak-ii-osvobozhdaet-predprinimatelei-ot-cifrovogo-rabstva.webp +0 -0
- package/src/img/examples/blog/post-2-avtomatizaciya-kontenta-kak-neiroseti-ubivayut-perfekcionizm-v-biznese.webp +0 -0
- package/src/img/examples/blog/post-3-laik-ne-valyuta-kak-avtomatizaciya-marketinga-spasaet-ot-lozhnyh-metrik.webp +0 -0
- package/src/img/examples/blog/post-5-5-fatalnyh-oshibok-marketinga-kotorye-ubivayut-startapy-na-starte.webp +0 -0
- package/src/img/examples/blog/post-6-5-strategii-kontent-marketinga-dlya-startapov-avtomatizaciya-i-revolyuciya.webp +0 -0
- package/src/img/examples/blog/post-7-viralnyi-kontent-ne-udacha-a-strategiya-avtomatizaciya-marketinga.webp +0 -0
- package/src/img/examples/blog/post-agent-experience-mcp-biznes-v-epohu-ii-agentov.webp +0 -0
- package/src/img/examples/blog/post_1_jsonld_guide.webp +0 -0
- package/src/img/examples/blog/tr-post-1.webp +0 -0
- package/src/layouts/BaseLayout.astro +59 -0
- package/src/pages/404.astro +24 -0
- package/src/pages/[...id].astro +50 -0
- package/src/pages/about.astro +0 -0
- package/src/pages/authors/[...page].astro +105 -0
- package/src/pages/authors/[id].astro +165 -0
- package/src/pages/blog/[...page].astro +59 -0
- package/src/pages/blog/[id].astro +175 -0
- package/src/pages/index.astro +90 -0
- package/src/pages/products/[...page].astro +50 -0
- package/src/pages/products/[id].astro +221 -0
- package/src/pages/projects/[...page].astro +74 -0
- package/src/pages/projects/[id].astro +165 -0
- package/src/pages/projects/tags/[id]/[...page].astro +58 -0
- package/src/pages/rss.xml.js +5 -0
- package/src/pages/tags/[id]/[...page].astro +110 -0
- package/src/pages/tags/index.astro +124 -0
- package/src/scripts/infoCardFadeIn.js +22 -0
- package/src/styles/global.css +272 -0
- package/src/utils/common-utils.ts +0 -0
- package/src/utils/content-loader.ts +14 -0
- package/src/utils/data-utils.ts +49 -0
- package/src/utils/featuredManager.ts +118 -0
- package/src/utils/posts.ts +43 -0
- package/src/utils/reading-time.ts +28 -0
- package/src/utils/remark-slugify.js +8 -0
- package/src/utils/rss.ts +23 -0
- package/typograf-batch.js +49 -0
@@ -0,0 +1,379 @@
|
|
1
|
+
---
|
2
|
+
import { slugify } from '../utils/common-utils';
|
3
|
+
import TagPill from './TagPill.astro';
|
4
|
+
import CopyLinkButton from './CopyLinkButton.astro';
|
5
|
+
import ShareLink from './ShareLink.astro';
|
6
|
+
import ShareIcon from './ShareIcon.astro';
|
7
|
+
import { maugliConfig } from '../config/maugli.config';
|
8
|
+
import { LANGUAGES } from '../i18n/languages';
|
9
|
+
|
10
|
+
export interface Props {
|
11
|
+
tags?: string[];
|
12
|
+
shareUrl?: string;
|
13
|
+
title?: string;
|
14
|
+
basePath?: string;
|
15
|
+
}
|
16
|
+
|
17
|
+
const { tags = [], shareUrl = '', title = '', basePath = '/blog' } = Astro.props;
|
18
|
+
|
19
|
+
// Определяем куда ведут теги
|
20
|
+
const tagsBasePath = basePath === '/projects' ? '/projects/tags' : '/tags';
|
21
|
+
|
22
|
+
const lang = typeof maugliConfig.defaultLang === 'string' ? maugliConfig.defaultLang : 'en';
|
23
|
+
const languageObj = LANGUAGES.find((l) => l.code === lang) || LANGUAGES.find((l) => l.code === 'en');
|
24
|
+
const fallbackDict = LANGUAGES.find((l) => l.code === 'en')?.dict || {};
|
25
|
+
const dict = languageObj?.dict && Object.keys(languageObj.dict).length > 0 ? languageObj.dict : fallbackDict;
|
26
|
+
const tagsSection = (dict as any).tagsSection || (fallbackDict as any).tagsSection || {};
|
27
|
+
const buttons = (dict as any).buttons || (fallbackDict as any).buttons || {};
|
28
|
+
|
29
|
+
const shareLinks = [
|
30
|
+
{
|
31
|
+
name: 'Twitter',
|
32
|
+
url: `https://twitter.com/intent/tweet?text=${encodeURIComponent(title)}&url=${encodeURIComponent(shareUrl)}`,
|
33
|
+
icon: 'twitter' as const
|
34
|
+
},
|
35
|
+
{
|
36
|
+
name: 'Telegram',
|
37
|
+
url: `https://t.me/share/url?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(title)}`,
|
38
|
+
icon: 'telegram' as const
|
39
|
+
},
|
40
|
+
{
|
41
|
+
name: 'LinkedIn',
|
42
|
+
url: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}`,
|
43
|
+
icon: 'linkedin' as const
|
44
|
+
},
|
45
|
+
{
|
46
|
+
name: 'WhatsApp',
|
47
|
+
url: `https://wa.me/?text=${encodeURIComponent(title + ' ' + shareUrl)}`,
|
48
|
+
icon: 'whatsapp' as const
|
49
|
+
},
|
50
|
+
{
|
51
|
+
name: 'Facebook',
|
52
|
+
url: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(shareUrl)}`,
|
53
|
+
icon: 'facebook' as const
|
54
|
+
}
|
55
|
+
];
|
56
|
+
---
|
57
|
+
|
58
|
+
<div class="w-full mb-2 rounded-custom border border-[var(--border-main)] py-6 px-8 flex-col gap-3 card-blur tags-share-container hidden md:flex">
|
59
|
+
<!-- Теги -->
|
60
|
+
{
|
61
|
+
tags.length > 0 && (
|
62
|
+
<div class="flex flex-col gap-3">
|
63
|
+
<h3 class="font-serif font-bold text-[18px] leading-[100%] text-[var(--text-heading)] flex-none">{tagsSection.allTags || 'Tags:'}</h3>
|
64
|
+
<div class="flex flex-wrap gap-2">
|
65
|
+
{tags.map((tag) => (
|
66
|
+
<TagPill tag={tag} href={`${tagsBasePath}/${slugify(tag)}`} />
|
67
|
+
))}
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
)
|
71
|
+
}
|
72
|
+
|
73
|
+
<!-- Кнопки шаринга -->
|
74
|
+
<div class="flex flex-col gap-3">
|
75
|
+
<h3 class="font-serif font-bold text-[18px] leading-[100%] text-[var(--text-heading)] flex-none">{buttons.share || 'Share Article'}</h3>
|
76
|
+
<div class="flex flex-wrap gap-2 share-buttons">
|
77
|
+
<a
|
78
|
+
class="share-link share-button"
|
79
|
+
href={shareLinks[0].url}
|
80
|
+
target="_blank"
|
81
|
+
rel="noopener noreferrer external"
|
82
|
+
title={shareLinks[0].name}
|
83
|
+
aria-label={shareLinks[0].name}
|
84
|
+
tabindex="0"
|
85
|
+
>
|
86
|
+
<span class="share-icon" aria-label="Twitter">
|
87
|
+
<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
88
|
+
<path d="M11.0207 8.96875L18.7675 19.0295H17.0129L9.26554 8.96875H11.0207Z" fill="currentColor" fill-opacity="0.8"></path>
|
89
|
+
<path
|
90
|
+
fill-rule="evenodd"
|
91
|
+
clip-rule="evenodd"
|
92
|
+
d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM7.61466 8.16667L12.5701 14.6021L7.58333 19.8333H8.70614L13.0709 15.2521L16.5982 19.8333H20.4167L15.1838 13.0367L19.8236 8.16667H18.7031L14.683 12.385L11.4354 8.16667H7.61466Z"
|
93
|
+
fill="currentColor"
|
94
|
+
fill-opacity="0.8"></path>
|
95
|
+
</svg>
|
96
|
+
</span>
|
97
|
+
</a>
|
98
|
+
<a
|
99
|
+
class="share-link share-button"
|
100
|
+
href={shareLinks[1].url}
|
101
|
+
target="_blank"
|
102
|
+
rel="noopener noreferrer external"
|
103
|
+
title={shareLinks[1].name}
|
104
|
+
aria-label={shareLinks[1].name}
|
105
|
+
tabindex="0"
|
106
|
+
>
|
107
|
+
<span class="share-icon" aria-label="Telegram">
|
108
|
+
<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
109
|
+
<path
|
110
|
+
fill-rule="evenodd"
|
111
|
+
clip-rule="evenodd"
|
112
|
+
d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM19.209 8.16667C18.7423 8.17491 18.0258 8.4236 14.5799 9.85685C13.373 10.3589 10.9608 11.3981 7.34351 12.974C6.75617 13.2076 6.44818 13.4365 6.42008 13.6599C6.36633 14.0889 6.98397 14.2225 7.76107 14.4751C8.39458 14.681 9.24686 14.9218 9.68994 14.9314C10.0918 14.94 10.5409 14.7747 11.0361 14.4347C14.4155 12.1535 16.1602 11.0002 16.2701 10.9751C16.3473 10.9576 16.4545 10.9352 16.527 10.9996C16.5993 11.0639 16.5922 11.1858 16.5846 11.2189C16.5231 11.4808 13.3495 14.3679 13.1654 14.5588C12.4672 15.284 11.6731 15.7276 12.8983 16.535C13.9584 17.2336 14.5753 17.6796 15.6674 18.3955C16.3653 18.853 16.9127 19.3955 17.6333 19.3292C17.9648 19.2986 18.3076 18.9868 18.4815 18.0571C18.8926 15.8594 19.7007 11.0972 19.8875 9.13509C19.9037 8.96324 19.8829 8.7434 19.8664 8.64689C19.8498 8.55033 19.8153 8.41263 19.6898 8.31079C19.5412 8.19027 19.3117 8.16489 19.209 8.16667Z"
|
113
|
+
fill="currentColor"
|
114
|
+
fill-opacity="0.8"></path>
|
115
|
+
</svg>
|
116
|
+
</span>
|
117
|
+
</a>
|
118
|
+
<a
|
119
|
+
class="share-link share-button"
|
120
|
+
href={shareLinks[2].url}
|
121
|
+
target="_blank"
|
122
|
+
rel="noopener noreferrer external"
|
123
|
+
title={shareLinks[2].name}
|
124
|
+
aria-label={shareLinks[2].name}
|
125
|
+
tabindex="0"
|
126
|
+
>
|
127
|
+
<span class="share-icon" aria-label="LinkedIn">
|
128
|
+
<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
129
|
+
<path
|
130
|
+
d="M16.4889 12.0575C17.6633 12.0575 18.9321 12.7547 18.9321 14.7964L18.931 18.9321H16.8272V15.2795C16.8272 14.2022 16.369 13.8695 15.7779 13.8695C15.1538 13.8697 14.5417 14.3406 14.5417 15.3068V18.9321H12.4368V12.2449H14.4609V13.1717H14.4882C14.6914 12.7605 15.4029 12.0575 16.4889 12.0575Z"
|
131
|
+
fill="currentColor"
|
132
|
+
fill-opacity="0.8"></path>
|
133
|
+
<path d="M11.1728 18.9264H9.06787V12.2403H11.1728V18.9264Z" fill="currentColor" fill-opacity="0.8"></path>
|
134
|
+
<path
|
135
|
+
d="M9.89274 8.91919C10.127 8.87322 10.3702 8.89802 10.5906 8.98983C10.8109 9.08163 10.9989 9.23671 11.1312 9.4353C11.2636 9.63401 11.3342 9.8676 11.334 10.1064C11.3362 10.2662 11.3066 10.4249 11.2463 10.5729C11.1859 10.7209 11.0959 10.855 10.9825 10.9677C10.8691 11.0803 10.7344 11.1692 10.586 11.2286C10.4376 11.288 10.2787 11.3168 10.1189 11.3135C9.88021 11.3121 9.64736 11.2403 9.44954 11.1067C9.25169 10.973 9.09731 10.7837 9.00692 10.5627C8.9166 10.3417 8.89395 10.0987 8.94141 9.86483C8.9889 9.6309 9.10476 9.41613 9.27409 9.24788C9.44338 9.07974 9.6586 8.96517 9.89274 8.91919Z"
|
136
|
+
fill="currentColor"
|
137
|
+
fill-opacity="0.8"></path>
|
138
|
+
<path
|
139
|
+
fill-rule="evenodd"
|
140
|
+
clip-rule="evenodd"
|
141
|
+
d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM8.03337 7C7.75931 7.00003 7.49628 7.1087 7.30249 7.30249C7.1087 7.49628 7.00003 7.75931 7 8.03337V19.9666C7.00003 20.2407 7.1087 20.5037 7.30249 20.6975C7.49628 20.8913 7.75931 21 8.03337 21H19.9666C20.2407 21 20.5037 20.8913 20.6975 20.6975C20.8913 20.5037 21 20.2407 21 19.9666V8.03337C21 7.75931 20.8913 7.49628 20.6975 7.30249C20.5037 7.1087 20.2407 7.00003 19.9666 7H8.03337Z"
|
142
|
+
fill="currentColor"
|
143
|
+
fill-opacity="0.8"></path>
|
144
|
+
</svg>
|
145
|
+
</span>
|
146
|
+
</a>
|
147
|
+
<a
|
148
|
+
class="share-link share-button"
|
149
|
+
href={shareLinks[3].url}
|
150
|
+
target="_blank"
|
151
|
+
rel="noopener noreferrer external"
|
152
|
+
title={shareLinks[3].name}
|
153
|
+
aria-label={shareLinks[3].name}
|
154
|
+
tabindex="0"
|
155
|
+
>
|
156
|
+
<span class="share-icon" aria-label="WhatsApp">
|
157
|
+
<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
158
|
+
<path
|
159
|
+
fill-rule="evenodd"
|
160
|
+
clip-rule="evenodd"
|
161
|
+
d="M14.0302 8.17464C15.5779 8.17467 17.0352 8.7736 18.1283 9.86483C19.2214 10.9561 19.8231 12.4032 19.8231 13.9436C19.823 17.1241 17.2225 19.7091 14.0302 19.7091H14.0268C12.9871 19.7058 11.9674 19.4299 11.0782 18.9042L10.8674 18.7778L8.6748 19.3497L9.25985 17.2237L9.12256 17.0044C8.5409 16.0861 8.23673 15.0247 8.23673 13.9368C8.23675 10.7562 10.8377 8.17131 14.0302 8.17464ZM11.563 10.733C11.446 10.733 11.2586 10.7759 11.0981 10.9489C10.9377 11.1219 10.4897 11.5414 10.4897 12.3964C10.4898 13.248 11.1148 14.0731 11.2018 14.1897C11.2887 14.3061 12.4088 16.1125 14.1772 16.8079C15.648 17.3868 15.9491 17.2702 16.2667 17.2402C16.5844 17.2101 17.296 16.8211 17.443 16.4154C17.5867 16.0096 17.5867 15.6639 17.5433 15.5905C17.4998 15.5173 17.3827 15.4736 17.2089 15.3871C17.0345 15.3003 16.1793 14.8819 16.0189 14.822C15.8585 14.7655 15.7417 14.7353 15.6281 14.908C15.5111 15.081 15.1764 15.4706 15.0761 15.5871C14.9759 15.7033 14.8721 15.7168 14.6984 15.6304C14.5245 15.5439 13.9632 15.3605 13.2982 14.7685C12.7802 14.3095 12.429 13.7408 12.3286 13.5676C12.2283 13.3946 12.3186 13.3015 12.4055 13.215C12.4824 13.1385 12.5795 13.0118 12.6664 12.9119C12.7532 12.8122 12.7834 12.7389 12.8402 12.6226C12.8969 12.5062 12.8699 12.4065 12.8265 12.3201C12.783 12.2369 12.4419 11.3782 12.2882 11.0355C12.1579 10.7463 12.021 10.7397 11.8974 10.7364C11.7971 10.7331 11.68 10.733 11.563 10.733Z"
|
162
|
+
fill="currentColor"
|
163
|
+
fill-opacity="0.8"></path>
|
164
|
+
<path
|
165
|
+
fill-rule="evenodd"
|
166
|
+
clip-rule="evenodd"
|
167
|
+
d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM14.0302 7C10.1892 7 7.0604 10.1107 7.06038 13.9368C7.05704 15.1577 7.37783 16.352 7.9895 17.4066L7 21L10.6903 20.0316C11.7098 20.5839 12.8567 20.8769 14.0234 20.877H14.0268C17.871 20.8769 21 17.7662 21 13.9402C21.0033 12.087 20.2777 10.3434 18.9606 9.03255C17.6469 7.72189 15.8954 7.00003 14.0302 7Z"
|
168
|
+
fill="currentColor"
|
169
|
+
fill-opacity="0.8"></path>
|
170
|
+
</svg>
|
171
|
+
</span>
|
172
|
+
</a>
|
173
|
+
<a
|
174
|
+
class="share-link share-button"
|
175
|
+
href={shareLinks[4].url}
|
176
|
+
target="_blank"
|
177
|
+
rel="noopener noreferrer external"
|
178
|
+
title={shareLinks[4].name}
|
179
|
+
aria-label={shareLinks[4].name}
|
180
|
+
tabindex="0"
|
181
|
+
>
|
182
|
+
<span class="share-icon" aria-label="Facebook">
|
183
|
+
<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
184
|
+
<path
|
185
|
+
fill-rule="evenodd"
|
186
|
+
clip-rule="evenodd"
|
187
|
+
d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM15.6685 7.58333C13.7987 7.58333 12.5776 8.72769 12.5776 10.7985V12.6191H10.5V15.0083H12.5776V20.7835C12.9947 20.8497 13.4217 20.8832 13.8564 20.8832C14.2911 20.8832 14.7177 20.8497 15.1348 20.7835V15.0083H17.0414L17.4043 12.6191H15.1348V11.0697C15.1348 10.416 15.4514 9.77824 16.4678 9.77824H17.5V7.74455C17.4937 7.74346 16.5605 7.58334 15.6685 7.58333Z"
|
188
|
+
fill="currentColor"
|
189
|
+
fill-opacity="0.8"></path>
|
190
|
+
</svg>
|
191
|
+
</span>
|
192
|
+
</a>
|
193
|
+
<CopyLinkButton url={shareUrl} />
|
194
|
+
</div>
|
195
|
+
</div>
|
196
|
+
</div>
|
197
|
+
|
198
|
+
<style>
|
199
|
+
.tags-share-container {
|
200
|
+
position: relative;
|
201
|
+
width: 100%;
|
202
|
+
border-radius: 8px 24px;
|
203
|
+
box-sizing: border-box;
|
204
|
+
}
|
205
|
+
|
206
|
+
.share-buttons {
|
207
|
+
display: flex;
|
208
|
+
flex-direction: row;
|
209
|
+
align-items: flex-start;
|
210
|
+
padding: 0px;
|
211
|
+
gap: 8px;
|
212
|
+
flex-wrap: wrap;
|
213
|
+
}
|
214
|
+
|
215
|
+
.share-link,
|
216
|
+
.share-button {
|
217
|
+
background: none;
|
218
|
+
color: var(--text-main);
|
219
|
+
border: none;
|
220
|
+
box-shadow: none;
|
221
|
+
width: 28px;
|
222
|
+
height: 28px;
|
223
|
+
display: flex;
|
224
|
+
align-items: center;
|
225
|
+
justify-content: center;
|
226
|
+
border-radius: 50%;
|
227
|
+
transition: transform 0.2s ease;
|
228
|
+
text-decoration: none;
|
229
|
+
cursor: pointer;
|
230
|
+
padding: 0;
|
231
|
+
}
|
232
|
+
.share-icon {
|
233
|
+
width: 28px;
|
234
|
+
height: 28px;
|
235
|
+
display: flex;
|
236
|
+
align-items: center;
|
237
|
+
justify-content: center;
|
238
|
+
transition: transform 0.2s ease;
|
239
|
+
color: var(--text-main);
|
240
|
+
min-width: 28px;
|
241
|
+
min-height: 28px;
|
242
|
+
}
|
243
|
+
.share-icon svg {
|
244
|
+
color: inherit;
|
245
|
+
width: 100%;
|
246
|
+
height: 100%;
|
247
|
+
display: block;
|
248
|
+
}
|
249
|
+
.share-link:hover,
|
250
|
+
.share-button:hover {
|
251
|
+
transform: scale(1.1);
|
252
|
+
background: none;
|
253
|
+
}
|
254
|
+
@media (min-width: 1024px) {
|
255
|
+
.share-link,
|
256
|
+
.share-button {
|
257
|
+
width: 36px;
|
258
|
+
height: 36px;
|
259
|
+
}
|
260
|
+
.share-icon {
|
261
|
+
width: 36px;
|
262
|
+
height: 36px;
|
263
|
+
min-width: 36px;
|
264
|
+
min-height: 36px;
|
265
|
+
}
|
266
|
+
}
|
267
|
+
html[data-theme='dark'] .share-link,
|
268
|
+
html[data-theme='dark'] .share-button {
|
269
|
+
color: var(--text-main);
|
270
|
+
background: none;
|
271
|
+
}
|
272
|
+
|
273
|
+
/* Кнопка копирования — адаптация под тему */
|
274
|
+
.copy-link-button {
|
275
|
+
border: none;
|
276
|
+
background: none;
|
277
|
+
color: var(--text-main);
|
278
|
+
cursor: pointer;
|
279
|
+
padding: 0;
|
280
|
+
display: flex;
|
281
|
+
align-items: center;
|
282
|
+
justify-content: center;
|
283
|
+
transition: transform 0.2s ease;
|
284
|
+
text-decoration: none;
|
285
|
+
width: 28px;
|
286
|
+
height: 28px;
|
287
|
+
box-shadow: none;
|
288
|
+
}
|
289
|
+
.copy-link-button .copy-icon {
|
290
|
+
width: 28px;
|
291
|
+
height: 28px;
|
292
|
+
display: flex;
|
293
|
+
align-items: center;
|
294
|
+
justify-content: center;
|
295
|
+
}
|
296
|
+
.copy-link-button .copy-icon svg {
|
297
|
+
width: 100%;
|
298
|
+
height: 100%;
|
299
|
+
fill: currentColor;
|
300
|
+
}
|
301
|
+
.copy-link-button:hover {
|
302
|
+
transform: scale(1.1);
|
303
|
+
background: none;
|
304
|
+
}
|
305
|
+
@media (min-width: 1024px) {
|
306
|
+
.copy-link-button {
|
307
|
+
width: 36px;
|
308
|
+
height: 36px;
|
309
|
+
}
|
310
|
+
.copy-link-button .copy-icon {
|
311
|
+
width: 36px;
|
312
|
+
height: 36px;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
/* Темная тема */
|
316
|
+
html[data-theme='dark'] .copy-link-button {
|
317
|
+
color: var(--text-main);
|
318
|
+
background: none;
|
319
|
+
}
|
320
|
+
/* Скрыть блок на мобиле */
|
321
|
+
@media (max-width: 767px) {
|
322
|
+
.tags-share-container {
|
323
|
+
display: none;
|
324
|
+
}
|
325
|
+
}
|
326
|
+
</style>
|
327
|
+
|
328
|
+
<script>
|
329
|
+
document.addEventListener('astro:page-load', () => {
|
330
|
+
// Обработчик для кнопки копирования ссылки в боковом блоке
|
331
|
+
const copyButtons = document.querySelectorAll('.tags-share-container .copy-link-btn');
|
332
|
+
|
333
|
+
copyButtons.forEach((button) => {
|
334
|
+
button.addEventListener('click', async (e) => {
|
335
|
+
e.preventDefault();
|
336
|
+
const url = button.getAttribute('data-url') || window.location.href;
|
337
|
+
|
338
|
+
try {
|
339
|
+
await navigator.clipboard.writeText(url);
|
340
|
+
|
341
|
+
// Системный звук копирования
|
342
|
+
try {
|
343
|
+
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
|
344
|
+
const oscillator = audioContext.createOscillator();
|
345
|
+
const gainNode = audioContext.createGain();
|
346
|
+
|
347
|
+
oscillator.connect(gainNode);
|
348
|
+
gainNode.connect(audioContext.destination);
|
349
|
+
|
350
|
+
oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
|
351
|
+
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
|
352
|
+
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
|
353
|
+
|
354
|
+
oscillator.start(audioContext.currentTime);
|
355
|
+
oscillator.stop(audioContext.currentTime + 0.1);
|
356
|
+
} catch (audioErr) {
|
357
|
+
console.log('Audio context not available');
|
358
|
+
}
|
359
|
+
|
360
|
+
// Меняем иконку на галочку
|
361
|
+
const shareIcon = button.querySelector('.share-icon');
|
362
|
+
if (shareIcon) {
|
363
|
+
const originalContent = shareIcon.innerHTML;
|
364
|
+
shareIcon.innerHTML = `<svg width="100%" height="100%" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
365
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 0C21.732 0 28 6.26801 28 14C28 21.732 21.732 28 14 28C6.26801 28 0 21.732 0 14C0 6.26801 6.26801 0 14 0ZM12.9307 16.8096L8 11.8789L5.87891 14L11.9395 20.0605C12.2322 20.3533 12.633 20.5119 13.0469 20.499C13.4607 20.4861 13.8511 20.3027 14.125 19.9922L22.6172 10.3672L20.3672 8.38281L12.9307 16.8096Z" fill="currentColor" fill-opacity="0.8"/>
|
366
|
+
</svg>`;
|
367
|
+
|
368
|
+
// Возвращаем исходную иконку через 5 секунд
|
369
|
+
setTimeout(() => {
|
370
|
+
shareIcon.innerHTML = originalContent;
|
371
|
+
}, 5000);
|
372
|
+
}
|
373
|
+
} catch (err) {
|
374
|
+
console.error('Failed to copy URL:', err);
|
375
|
+
}
|
376
|
+
});
|
377
|
+
});
|
378
|
+
});
|
379
|
+
</script>
|
@@ -0,0 +1,203 @@
|
|
1
|
+
---
|
2
|
+
import { maugliConfig } from '../config/maugli.config';
|
3
|
+
import { LANGUAGES } from '../i18n/languages';
|
4
|
+
export interface Props {
|
5
|
+
tags: Array<{
|
6
|
+
id: string;
|
7
|
+
name: string;
|
8
|
+
count: number;
|
9
|
+
isRubric?: boolean;
|
10
|
+
}>;
|
11
|
+
totalCount: number;
|
12
|
+
activeTagId?: string;
|
13
|
+
basePath?: string;
|
14
|
+
class?: string;
|
15
|
+
rubricImage?: string;
|
16
|
+
rubricDescription?: string;
|
17
|
+
rubricName?: string;
|
18
|
+
}
|
19
|
+
|
20
|
+
const { tags, totalCount, activeTagId, basePath = '/blog', class: className = '', rubricImage, rubricDescription = '', rubricName = '' } = Astro.props;
|
21
|
+
const isAllActive = !activeTagId; // "Все" активен, если нет активного тега
|
22
|
+
|
23
|
+
// Определяем куда ведет кнопка "Все" и куда ведут теги
|
24
|
+
const allHref = basePath === '/projects' ? '/projects' : '/blog';
|
25
|
+
const tagsBasePath = basePath === '/projects' ? '/projects/tags' : '/tags';
|
26
|
+
const lang = typeof maugliConfig.defaultLang === 'string' ? maugliConfig.defaultLang : 'en';
|
27
|
+
const languageObj = LANGUAGES.find((l) => l.code === lang) || LANGUAGES.find((l) => l.code === 'en');
|
28
|
+
const fallbackDict = LANGUAGES.find((l) => l.code === 'en')?.dict || {};
|
29
|
+
const dict = languageObj?.dict && Object.keys(languageObj.dict).length > 0 ? languageObj.dict : fallbackDict;
|
30
|
+
const tagsSection = (dict as any).tagsSection || (fallbackDict as any).tagsSection || {};
|
31
|
+
const allLabel = basePath === '/projects' ? tagsSection.allCases : tagsSection.allArticles;
|
32
|
+
const allTagsLabel = tagsSection.allTags;
|
33
|
+
|
34
|
+
// Fallback для изображения рубрики
|
35
|
+
const rubricImageFinal = rubricImage && rubricImage.length > 0 ? rubricImage : maugliConfig.defaultRubricImage;
|
36
|
+
---
|
37
|
+
|
38
|
+
{
|
39
|
+
(rubricName || rubricDescription) && (
|
40
|
+
<div class="flex flex-col sm:flex-row items-center sm:items-start gap-4 mb-6">
|
41
|
+
<img
|
42
|
+
src={rubricImageFinal}
|
43
|
+
alt={rubricName || tagsSection.rubricAlt}
|
44
|
+
class="w-20 h-20 sm:w-40 sm:h-40 object-cover rounded-[16px_48px_16px_48px] border border-[var(--border-main)]"
|
45
|
+
style="flex-shrink:0;"
|
46
|
+
/>
|
47
|
+
<div class="flex flex-col items-center sm:items-start text-center sm:text-left">
|
48
|
+
{rubricName && <h2 class="text-xl sm:text-2xl font-bold mb-2">{rubricName}</h2>}
|
49
|
+
{rubricDescription && <div class="text-base sm:text-lg text-[var(--text-muted)]">{rubricDescription}</div>}
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
)
|
53
|
+
}
|
54
|
+
|
55
|
+
<div class:list={['flex flex-wrap items-center gap-2 py-4 mb-6', className]}>
|
56
|
+
<!-- Десктопная версия -->
|
57
|
+
<div class="hidden sm:flex flex-wrap items-center gap-2">
|
58
|
+
<a
|
59
|
+
href={allHref}
|
60
|
+
aria-label={allLabel + ` (${totalCount})`}
|
61
|
+
class:list={[
|
62
|
+
'inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline transition-all duration-200 ease-in-out hover:-translate-y-px rounded-3xl',
|
63
|
+
isAllActive
|
64
|
+
? 'bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)] hover:bg-[var(--brand-color-60)]'
|
65
|
+
: 'border border-[var(--border-main)] text-[var(--text-heading)] hover:bg-[var(--bg-muted)]'
|
66
|
+
]}
|
67
|
+
>
|
68
|
+
{allLabel} ({totalCount})
|
69
|
+
</a>
|
70
|
+
{
|
71
|
+
tags.map((tag) => {
|
72
|
+
const isActive = activeTagId === tag.id;
|
73
|
+
const isRubric = tag.isRubric;
|
74
|
+
const ariaLabel = tagsSection.tagAriaLabel
|
75
|
+
? tagsSection.tagAriaLabel.replace('{name}', tag.name).replace('{count}', tag.count)
|
76
|
+
: `Tag: ${tag.name} (${tag.count})`;
|
77
|
+
return (
|
78
|
+
<a
|
79
|
+
href={`${tagsBasePath}/${tag.id}`}
|
80
|
+
aria-label={ariaLabel}
|
81
|
+
class:list={[
|
82
|
+
'inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline transition-all duration-200 ease-in-out hover:-translate-y-px rounded-3xl',
|
83
|
+
isActive
|
84
|
+
? 'bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)] hover:bg-[var(--brand-color-60)]'
|
85
|
+
: isRubric
|
86
|
+
? 'bg-[var(--bg-muted)] border border-[var(--border-main)] text-[var(--text-heading)] hover:bg-[var(--brand-color-20)]'
|
87
|
+
: 'border border-[var(--border-main)] text-[var(--text-muted)] opacity-75 hover:bg-[var(--bg-muted)]'
|
88
|
+
]}
|
89
|
+
>
|
90
|
+
{tag.name}
|
91
|
+
<span style="color: inherit; opacity: 0.6;"> ({tag.count})</span>
|
92
|
+
</a>
|
93
|
+
);
|
94
|
+
})
|
95
|
+
}
|
96
|
+
</div>
|
97
|
+
<!-- Мобильная версия -->
|
98
|
+
<div class="block sm:hidden w-full">
|
99
|
+
<input type="checkbox" id="tags-toggle" class="hidden peer" />
|
100
|
+
<div class="flex items-center justify-between w-full px-2">
|
101
|
+
{
|
102
|
+
isAllActive ? (
|
103
|
+
<a
|
104
|
+
href={allHref}
|
105
|
+
aria-label={allLabel + ` (${totalCount})`}
|
106
|
+
class="inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline rounded-3xl bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)]"
|
107
|
+
>
|
108
|
+
{allLabel} ({totalCount})
|
109
|
+
</a>
|
110
|
+
) : (
|
111
|
+
tags
|
112
|
+
.filter((tag) => activeTagId === tag.id)
|
113
|
+
.map((tag) => {
|
114
|
+
const ariaLabel = tagsSection.tagAriaLabel
|
115
|
+
? tagsSection.tagAriaLabel.replace('{name}', tag.name).replace('{count}', tag.count)
|
116
|
+
: `Tag: ${tag.name} (${tag.count})`;
|
117
|
+
return (
|
118
|
+
<a
|
119
|
+
href={`${tagsBasePath}/${tag.id}`}
|
120
|
+
aria-label={ariaLabel}
|
121
|
+
class="inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline rounded-3xl bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)]"
|
122
|
+
>
|
123
|
+
{tag.name}
|
124
|
+
<span style="color: inherit; opacity: 0.6;"> ({tag.count})</span>
|
125
|
+
</a>
|
126
|
+
);
|
127
|
+
})
|
128
|
+
)
|
129
|
+
}
|
130
|
+
<label for="tags-toggle" class="flex items-center gap-1 px-2 py-1 cursor-pointer" style="color: var(--text-muted); opacity: 0.6;">
|
131
|
+
<span>{allTagsLabel}</span>
|
132
|
+
<span class="arrow-wrap" style="display:inline-flex;align-items:center;">
|
133
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="color:inherit;" class="arrow-svg">
|
134
|
+
<g clip-path="url(#clip0_3691_7173)">
|
135
|
+
<path
|
136
|
+
d="M6.68112 2.28658L11.7136 7.31908C12.0951 7.70054 12.0951 8.319 11.7136 8.70045L11.6997 8.7144C11.3182 9.09586 10.6997 9.09586 10.3183 8.7144L5.28579 3.68191C4.90434 3.30045 4.90434 2.68199 5.28579 2.30054L5.29975 2.28658C5.6812 1.90513 6.29966 1.90513 6.68112 2.28658Z"
|
137
|
+
fill="currentColor"></path>
|
138
|
+
<path
|
139
|
+
d="M11.6997 7.28755L11.7136 7.3015C12.0951 7.68296 12.0951 8.30142 11.7136 8.68287L6.68112 13.7154C6.29966 14.0968 5.6812 14.0968 5.29975 13.7154L5.28579 13.7014C4.90434 13.32 4.90434 12.7015 5.28579 12.32L10.3183 7.28755C10.6997 6.90609 11.3182 6.90609 11.6997 7.28755Z"
|
140
|
+
fill="currentColor"></path>
|
141
|
+
</g>
|
142
|
+
<defs>
|
143
|
+
<clipPath id="clip0_3691_7173">
|
144
|
+
<rect width="7" height="12" fill="white" transform="matrix(-1 0 0 1 12 2)"></rect>
|
145
|
+
</clipPath>
|
146
|
+
</defs>
|
147
|
+
</svg>
|
148
|
+
</span>
|
149
|
+
</label>
|
150
|
+
<style>
|
151
|
+
.arrow-wrap .arrow-svg {
|
152
|
+
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
153
|
+
}
|
154
|
+
#tags-toggle:checked + div label .arrow-wrap .arrow-svg {
|
155
|
+
transform: rotate(90deg);
|
156
|
+
}
|
157
|
+
.tags-mobile-list {
|
158
|
+
max-height: 0;
|
159
|
+
opacity: 0;
|
160
|
+
overflow: hidden;
|
161
|
+
transition:
|
162
|
+
max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
163
|
+
opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
164
|
+
}
|
165
|
+
#tags-toggle:checked ~ .tags-mobile-list {
|
166
|
+
max-height: 500px;
|
167
|
+
opacity: 1;
|
168
|
+
}
|
169
|
+
</style>
|
170
|
+
</div>
|
171
|
+
<div class="tags-mobile-list flex-wrap gap-2 py-4 mb-6" style="margin-top: 8px;">
|
172
|
+
<a
|
173
|
+
href={allHref}
|
174
|
+
class:list={[
|
175
|
+
'inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline rounded-3xl',
|
176
|
+
isAllActive
|
177
|
+
? 'bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)] hover:bg-[var(--brand-color-60)]'
|
178
|
+
: 'border border-[var(--border-main)] text-[var(--text-heading)] hover:bg-[var(--bg-muted)]'
|
179
|
+
]}
|
180
|
+
>
|
181
|
+
{allLabel} ({totalCount})
|
182
|
+
</a>
|
183
|
+
{
|
184
|
+
tags.map((tag) => (
|
185
|
+
<a
|
186
|
+
href={`${tagsBasePath}/${tag.id}`}
|
187
|
+
class:list={[
|
188
|
+
'inline-flex items-center justify-center px-4 py-1.5 text-lg leading-[22px] font-inter font-normal whitespace-nowrap no-underline rounded-3xl',
|
189
|
+
activeTagId === tag.id
|
190
|
+
? 'bg-[var(--brand-color-20)] border border-[var(--brand-color)] text-[var(--brand-color)] hover:bg-[var(--brand-color-60)]'
|
191
|
+
: tag.isRubric
|
192
|
+
? 'bg-[var(--bg-muted)] border border-[var(--border-main)] text-[var(--text-heading)] hover:bg-[var(--brand-color-20)]'
|
193
|
+
: 'border border-[var(--border-main)] text-[var(--text-muted)] opacity-75 hover:bg-[var(--bg-muted)]'
|
194
|
+
]}
|
195
|
+
>
|
196
|
+
{tag.name}
|
197
|
+
<span style="color: inherit; opacity: 0.6;"> ({tag.count})</span>
|
198
|
+
</a>
|
199
|
+
))
|
200
|
+
}
|
201
|
+
</div>
|
202
|
+
</div>
|
203
|
+
</div>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
---
|
2
|
+
import { LANGUAGES } from '../i18n/languages';
|
3
|
+
import { maugliConfig } from '../config/maugli.config';
|
4
|
+
|
5
|
+
// Универсальный импорт словарей по доступным языкам
|
6
|
+
const dicts: Record<string, any> = {};
|
7
|
+
for (const lang of LANGUAGES) {
|
8
|
+
try {
|
9
|
+
dicts[lang.code] = await import(`../i18n/${lang.code}.json`).then((m) => m.default);
|
10
|
+
} catch {}
|
11
|
+
}
|
12
|
+
const lang: string = maugliConfig.defaultLang || 'en';
|
13
|
+
const dict = dicts[lang] || dicts['en'] || {};
|
14
|
+
const ariaLabel = dict.themeToggle?.ariaLabel || dicts['en']?.themeToggle?.ariaLabel;
|
15
|
+
---
|
16
|
+
|
17
|
+
<button
|
18
|
+
id="theme-toggle"
|
19
|
+
class="w-8 h-8 mr-4 flex items-center justify-center cursor-pointer transition-transform duration-200 hover:scale-110"
|
20
|
+
aria-label={ariaLabel}
|
21
|
+
>
|
22
|
+
<!-- Sun icon for dark mode (shows when dark theme is active) -->
|
23
|
+
<svg id="sun-icon" class="w-6 h-6 hidden dark:block" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
24
|
+
<path
|
25
|
+
d="M5 12C5 11.7348 4.89464 11.4804 4.70711 11.2929C4.51957 11.1054 4.26522 11 4 11H3C2.73478 11 2.48043 11.1054 2.29289 11.2929C2.10536 11.4804 2 11.7348 2 12C2 12.2652 2.10536 12.5196 2.29289 12.7071C2.48043 12.8946 2.73478 13 3 13H4C4.26522 13 4.51957 12.8946 4.70711 12.7071C4.89464 12.5196 5 12.2652 5 12ZM5.64 17L4.93 17.71C4.74375 17.8974 4.63921 18.1508 4.63921 18.415C4.63921 18.6792 4.74375 18.9326 4.93 19.12C5.11736 19.3063 5.37081 19.4108 5.635 19.4108C5.89919 19.4108 6.15264 19.3063 6.34 19.12L7.05 18.41C7.21383 18.2187 7.29943 17.9726 7.28971 17.7209C7.27999 17.4693 7.17566 17.2305 6.99756 17.0524C6.81947 16.8743 6.58073 16.77 6.32905 16.7603C6.07738 16.7506 5.8313 16.8362 5.64 17ZM12 5C12.2652 5 12.5196 4.89464 12.7071 4.70711C12.8946 4.51957 13 4.26522 13 4V3C13 2.73478 12.8946 2.48043 12.7071 2.29289C12.5196 2.10536 12.2652 2 12 2C11.7348 2 11.4804 2.10536 11.2929 2.29289C11.1054 2.48043 11 2.73478 11 3V4C11 4.26522 11.1054 4.51957 11.2929 4.70711C11.4804 4.89464 11.7348 5 12 5ZM17.66 7.34C17.9223 7.3389 18.1737 7.23474 18.36 7.05L19.07 6.34C19.1747 6.25035 19.2597 6.14003 19.3197 6.01597C19.3797 5.89191 19.4135 5.75677 19.4188 5.61905C19.4241 5.48133 19.4009 5.344 19.3506 5.21568C19.3004 5.08735 19.2241 4.9708 19.1266 4.87335C19.0292 4.77589 18.9126 4.69964 18.7843 4.64936C18.656 4.59909 18.5187 4.57588 18.3809 4.5812C18.2432 4.58652 18.1081 4.62025 17.984 4.68027C17.86 4.7403 17.7496 4.82532 17.66 4.93L17 5.64C16.8137 5.82736 16.7092 6.08081 16.7092 6.345C16.7092 6.60919 16.8137 6.86264 17 7.05C17.1763 7.22536 17.4116 7.32875 17.66 7.34ZM5.66 7.05C5.84626 7.23474 6.09766 7.3389 6.36 7.34C6.49161 7.34076 6.62207 7.31554 6.74391 7.26577C6.86574 7.21601 6.97656 7.14268 7.07 7.05C7.25625 6.86264 7.36079 6.60919 7.36079 6.345C7.36079 6.08081 7.25625 5.82736 7.07 5.64L6.36 4.93C6.26742 4.8361 6.15725 4.76136 6.03578 4.71005C5.91432 4.65873 5.78393 4.63184 5.65207 4.63091C5.52021 4.62998 5.38946 4.65503 5.26728 4.70463C5.14511 4.75424 5.0339 4.82742 4.94 4.92C4.8461 5.01258 4.77136 5.12275 4.72005 5.24422C4.66873 5.36568 4.64184 5.49607 4.64091 5.62793C4.63903 5.89423 4.74302 6.15037 4.93 6.34L5.66 7.05ZM21 11H20C19.7348 11 19.4804 11.1054 19.2929 11.2929C19.1054 11.4804 19 11.7348 19 12C19 12.2652 19.1054 12.5196 19.2929 12.7071C19.4804 12.8946 19.7348 13 20 13H21C21.2652 13 21.5196 12.8946 21.7071 12.7071C21.8946 12.5196 22 12.2652 22 12C22 11.7348 21.8946 11.4804 21.7071 11.2929C21.5196 11.1054 21.2652 11 21 11ZM18.36 17C18.17 16.8943 17.9508 16.8534 17.7355 16.8835C17.5202 16.9136 17.3205 17.0131 17.1668 17.1668C17.0131 17.3205 16.9136 17.5202 16.8835 17.7355C16.8534 17.9508 16.8943 18.17 17 18.36L17.71 19.07C17.8974 19.2563 18.1508 19.3608 18.415 19.3608C18.6792 19.3608 18.9326 19.2563 19.12 19.07C19.3063 18.8826 19.4108 18.6292 19.4108 18.365C19.4108 18.1008 19.3063 17.8474 19.12 17.66L18.36 17ZM12 6.5C10.9122 6.5 9.84883 6.82257 8.94436 7.42692C8.03989 8.03126 7.33494 8.89025 6.91866 9.89524C6.50238 10.9002 6.39346 12.0061 6.60568 13.073C6.8179 14.1399 7.34172 15.1199 8.11091 15.8891C8.8801 16.6583 9.86011 17.1821 10.927 17.3943C11.9939 17.6065 13.0998 17.4976 14.1048 17.0813C15.1098 16.6651 15.9687 15.9601 16.5731 15.0556C17.1774 14.1512 17.5 13.0878 17.5 12C17.4974 10.5421 16.917 9.14471 15.8862 8.11383C14.8553 7.08295 13.4579 6.50264 12 6.5ZM12 15.5C11.3078 15.5 10.6311 15.2947 10.0555 14.9101C9.47993 14.5256 9.03133 13.9789 8.76642 13.3394C8.50151 12.6999 8.4322 11.9961 8.56725 11.3172C8.7023 10.6382 9.03564 10.0146 9.52513 9.52513C10.0146 9.03564 10.6382 8.7023 11.3172 8.56725C11.9961 8.4322 12.6999 8.50151 13.3394 8.76642C13.9789 9.03133 14.5256 9.47993 14.9101 10.0555C15.2947 10.6311 15.5 11.3078 15.5 12C15.5 12.9283 15.1313 13.8185 14.4749 14.4749C13.8185 15.1313 12.9283 15.5 12 15.5ZM12 19C11.7348 19 11.4804 19.1054 11.2929 19.2929C11.1054 19.4804 11 19.7348 11 20V21C11 21.2652 11.1054 21.5196 11.2929 21.7071C11.4804 21.8946 11.7348 22 12 22C12.2652 22 12.5196 21.8946 12.7071 21.7071C12.8946 21.5196 13 21.2652 13 21V20C13 19.7348 12.8946 19.4804 12.7071 19.2929C12.5196 19.1054 12.2652 19 12 19Z"
|
26
|
+
fill="var(--text-heading)"></path>
|
27
|
+
</svg>
|
28
|
+
|
29
|
+
<!-- Moon icon for light mode (shows when light theme is active) -->
|
30
|
+
<svg id="moon-icon" class="w-6 h-6 block dark:hidden" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
31
|
+
<path
|
32
|
+
fill-rule="evenodd"
|
33
|
+
clip-rule="evenodd"
|
34
|
+
d="M12.1981 18.3607C13.3886 18.3595 14.5563 18.0344 15.5762 17.4204C16.5961 16.8064 17.4298 15.9266 17.988 14.8751C12.9147 15.3054 8.69375 11.0983 9.12403 6.01188C8.07276 6.57027 7.19313 7.40404 6.5793 8.42393C5.96547 9.44382 5.64054 10.6114 5.6393 11.8018C5.6393 15.4183 8.58168 18.3607 12.1981 18.3607ZM9.54096 4.05236C10.3584 3.77139 10.9876 4.67308 10.8223 5.52148C9.96102 9.94161 14.0407 14.0553 18.4792 13.1802C19.3272 13.013 20.2286 13.6415 19.9476 14.4589C18.8495 17.6543 15.8222 20 12.1981 20C7.67042 20 4 16.3295 4 11.8018C4 8.176 6.34692 5.15023 9.54096 4.05236Z"
|
35
|
+
fill="var(--text-main)"></path>
|
36
|
+
</svg>
|
37
|
+
</button>
|
38
|
+
|
39
|
+
<script>
|
40
|
+
document.addEventListener('astro:page-load', () => {
|
41
|
+
const themeToggle = document.getElementById('theme-toggle');
|
42
|
+
|
43
|
+
function toggleTheme() {
|
44
|
+
const html = document.documentElement;
|
45
|
+
const currentTheme = localStorage.getItem('theme');
|
46
|
+
|
47
|
+
if (currentTheme === 'dark') {
|
48
|
+
html.classList.remove('dark');
|
49
|
+
localStorage.setItem('theme', 'light');
|
50
|
+
} else {
|
51
|
+
html.classList.add('dark');
|
52
|
+
localStorage.setItem('theme', 'dark');
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
themeToggle?.addEventListener('click', toggleTheme);
|
57
|
+
});
|
58
|
+
</script>
|