Отзывы и предложения к софту от AleXStam
  • Страница 3 из 3
  • «
  • 1
  • 2
  • 3
Поговорим о...
{{- $link := .Get "link" -}}
{{- $title := .Get "title" -}}
{{- $iconName := .Get "icon" -}}
{{- $icon := "" -}}
{{- $subtitle := .Get "subtitle" -}}
{{- $image := .Get "image" -}}
{{- $width := 0 -}}
{{- $height := 0 -}}
{{- $imageStyle := .Get "imageStyle" -}}
{{- $tag := .Get "tag" -}}
{{- $tagType := .Get "tagType" -}}

{{/* ========== УЛУЧШЕННЫЙ КОД ДЛЯ ИКОНОК ========== */}}
{{- if $iconName -}}
{{/* Попытка 1: Получить из site.Data.icons */}}
{{- if and site.Data.icons (index site.Data.icons $iconName) -}}
{{- $icon = (index site.Data.icons $iconName) | safeHTML -}}
{{/* Для отладки можно включить: {{/* {{ printf "Found icon '%s' in site.Data.icons" $iconName }} */}} */}}

{{/* Попытка 2: Использовать встроенные иконки (fallback) */}}
{{- else -}}
{{- $fallbackIcons := dict
"book-open" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path></svg>`
"globe-alt" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>`
"clipboard-check" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect><path d="M9 14l2 2 4-4"></path></svg>`
"download" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`
"file" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline></svg>`
"home" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>`
"settings" `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`
-}}

{{- $fallbackIcon := index $fallbackIcons $iconName -}}
{{- if $fallbackIcon -}}
{{- $icon = $fallbackIcon | safeHTML -}}
{{- warnf "Используется fallback иконка для '%s'" $iconName -}}
{{/* Попытка 3: Создать простую иконку с текстом */}}
{{- else -}}
{{- $icon = (printf `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" stroke-width="1"></rect>
<text x="12" y="12" text-anchor="middle" dy=".3em" font-size="5" font-family="Arial, sans-serif">%s</text>
</svg>` (substr $iconName 0 6)) | safeHTML -}}
{{- warnf "Создана простая иконка для '%s'" $iconName -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/* ========== КОНЕЦ КОДА ДЛЯ ИКОНОК ========== */}}

{{/* Остальной код без изменений */}}
{{- $method := .Get "method" | default "Resize" | humanize -}}
{{- $options := .Get "options" | default "800x webp q80" -}}
{{- $process := .Get "process" | default (printf "%s %s" $method $options) -}}

{{- if and $image (not (urls.Parse $image).Scheme) -}}
{{- with or (.Page.Resources.Get $image) (resources.Get $image) -}}
{{- if not (eq .MediaType.SubType "svg") -}}
{{- $processed := .Process $process -}}
{{- $width = $processed.Width -}}
{{- $height = $processed.Height -}}
{{- $image = $processed.RelPermalink -}}
{{- end -}}
{{- else -}}
{{- if hasPrefix $image "/" -}}
{{- $image = relURL (strings.TrimPrefix "/" $image) -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{- partial "shortcodes/card" (dict
"page" .Page
"link" $link
"title" $title
"icon" $icon
"subtitle" $subtitle
"image" $image
"width" $width
"height" $height
"imageStyle" $imageStyle
"tag" $tag
"tagType" $tagType
) -}}
Похоже, что проблема не в получении иконки, а в её передаче или отображении в конечном шаблоне shortcodes/card. Давайте решим это:

Вариант: Полная переделка с безопасной передачей данных

```go-html-template
{{- $link := .Get "link" -}}
{{- $title := .Get "title" -}}
{{- $iconName := .Get "icon" -}}
{{- $icon := "" -}}
{{- $subtitle := .Get "subtitle" -}}
{{- $image := .Get "image" -}}
{{- $width := 0 -}}
{{- $height := 0 -}}
{{- $imageStyle := .Get "imageStyle" -}}
{{- $tag := .Get "tag" -}}
{{- $tagType := .Get "tagType" -}}

{{/* ========== КОД ДЛЯ ИКОНОК БЕЗОПАСНЫЙ ========== */}}
{{- if $iconName -}}
{{/* Создаем безопасный SVG (без кавычек в атрибутах) */}}
{{- $fallbackIcons := dict
"book-open" `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z'/><path d='M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z'/></svg>`
"globe-alt" `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><line x1='2' y1='12' x2='22' y2='12'/><path d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/></svg>`
"clipboard-check" `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/><rect x='8' y='2' width='8' height='4' rx='1' ry='1'/><path d='M9 14l2 2 4-4'/></svg>`
"download" `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/><polyline points='7 10 12 15 17 10'/><line x1='12' y1='15' x2='12' y2='3'/></svg>`
-}}

{{/* Пробуем получить из data */}}
{{- $foundIcon := false -}}
{{- if site.Data.icons -}}
{{- $dataIcon := index site.Data.icons $iconName -}}
{{- if $dataIcon -}}
{{- $icon = $dataIcon -}}
{{- $foundIcon = true -}}
{{- end -}}
{{- end -}}

{{/* Если не нашли в data, используем fallback */}}
{{- if not $foundIcon -}}
{{- $fallbackIcon := index $fallbackIcons $iconName -}}
{{- if $fallbackIcon -}}
{{- $icon = $fallbackIcon -}}
{{- warnf "Используется fallback иконка для '%s'" $iconName -}}
{{- else -}}
{{/* Простая иконка-заглушка */}}
{{- $icon = printf "<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><rect x='2' y='2' width='20' height='20' rx='4' fill='#f0f0f0' stroke='#999' stroke-width='1'/><text x='12' y='14' text-anchor='middle' font-size='7' font-family='Arial'>%s</text></svg>" (substr $iconName 0 3) -}}
{{- warnf "Создана простая иконка для '%s'" $iconName -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/* ========== КОНЕЦ КОДА ДЛЯ ИКОНОК ========== */}}

{{/* Остальной код без изменений */}}
{{- $method := .Get "method" | default "Resize" | humanize -}}
{{- $options := .Get "options" | default "800x webp q80" -}}
{{- $process := .Get "process" | default (printf "%s %s" $method $options) -}}

{{- if and $image (not (urls.Parse $image).Scheme) -}}
{{- with or (.Page.Resources.Get $image) (resources.Get $image) -}}
{{- if not (eq .MediaType.SubType "svg") -}}
{{- $processed := .Process $process -}}
{{- $width = $processed.Width -}}
{{- $height = $processed.Height -}}
{{- $image = $processed.RelPermalink -}}
{{- end -}}
{{- else -}}
{{- if hasPrefix $image "/" -}}
{{- $image = relURL (strings.TrimPrefix "/" $image) -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/* Передаем данные в partial БЕЗ safeHTML здесь */}}
{{- partial "shortcodes/card" (dict
"page" .Page
"link" $link
"title" $title
"icon" $icon /* передаем как есть, без safeHTML */
"subtitle" $subtitle
"image" $image
"width" $width
"height" $height
"imageStyle" $imageStyle
"tag" $tag
"tagType" $tagType
) -}}
```

Также обновите файл shortcodes/card.html:

```go-html-template
{{/* layouts/shortcodes/card.html или partials/shortcodes/card.html */}}
{{- $icon := .icon -}}
{{- $title := .title -}}
{{- $link := .link -}}
{{- $subtitle := .subtitle -}}
{{- $image := .image -}}
{{- $page := .page -}}

<div class="card">
{{ if $icon }}
<div class="card-icon">
{{ $icon | safeHTML }} <!-- Здесь применяем safeHTML -->
</div>
{{ end }}

<div class="card-content">
<h3>{{ $title }}</h3>
{{ if $subtitle }}
<p class="card-subtitle">{{ $subtitle }}</p>
{{ end }}
</div>
</div>
```

Если проблема в самом шаблоне card, попробуйте это:

Создайте простой тестовый шаблон:

```go-html-template
{{/* layouts/partials/test-card.html */}}
{{- $icon := .icon -}}
{{- $title := .title -}}

<div class="test-card">
{{ if $icon }}
<div>Иконка: {{ $icon }}</div>
{{ else }}
<div>Нет иконки</div>
{{ end }}
<div>Заголовок: {{ $title }}</div>
</div>
```

И используйте его временно в card.html:

```go-html-template
{{/* Вместо partial "shortcodes/card" */}}
{{- partial "test-card" (dict
"icon" $icon
"title" $title
) -}}
```

Альтернатива: Передавайте только имя иконки

```go-html-template
{{/* В card.html (шорткод) передаем только имя */}}
{{- partial "shortcodes/card" (dict
"page" .Page
"link" $link
"title" $title
"iconName" $iconName /* передаем имя, не SVG */
"icon" $icon /* и SVG как запасной вариант */
"subtitle" $subtitle
"image" $image
"width" $width
"height" $height
"imageStyle" $imageStyle
"tag" $tag
"tagType" $tagType
) -}}

{{/* В shortcodes/card.html получаем иконку */}}
{{- $iconName := .iconName -}}
{{- $icon := .icon -}}

{{/* Если передан SVG, используем его */}}
{{ if $icon }}
<div class="icon">{{ $icon | safeHTML }}</div>
{{ else if $iconName }}
{{/* Иначе ищем по имени */}}
{{ with site.Data.icons }}
{{ with index . $iconName }}
<div class="icon">{{ . | safeHTML }}</div>
{{ end }}
{{ end }}
{{ end }}
```

Быстрое решение для теста:

Замените в card.html вывод на самый простой:

```go-html-template
{{/* Просто выводим карточку без partial */}}
<div class="card">
{{ if $icon }}
<div class="card-icon">[ИКОНКА ЕСТЬ]</div>
{{ else }}
<div class="card-icon">[НЕТ ИКОНКИ]</div>
{{ end }}
<h3><a href="{{ $link }}">{{ $title }}</a></h3>
{{ if $subtitle }}<p>{{ $subtitle }}</p>{{ end }}
</div>
```

Если это работает, значит проблема в partial shortcodes/card. Если не работает - проблема в данных или их передаче.

Попробуйте первый вариант с заменой кавычек в SVG на одинарные - это часто решает проблемы с парсингом.
{{/* layouts/shortcodes/cardinfo.html */}}
{{ $link := .Get "link" }}
{{ $title := .Get "title" }}
{{ $desc := .Get "desc" | default "" }}
{{ $date := .Get "date" }}
{{ $audience := .Get "audience" }}
{{ $tag := .Get "tag" }}
{{ $tagtype := .Get "tagtype" | default "default" }}
{{ $icon := .Get "icon" }}
{{ $iconsize := .Get "iconsize" | default "24px" }}

<div class="info-card">
<a href="{{ $link }}" class="info-card-link" target="_blank">
<div class="info-card-header">
<div class="info-card-left">
{{ if $icon }}
<span class="info-card-title-icon">
{{ if .Site.Data.icons }}
{{ $iconData := index .Site.Data.icons $icon }}
{{ if $iconData }}
{{ $iconSvg := replaceRE "<svg" (printf "<svg width='%s' height='%s'" $iconsize $iconsize) $iconData }}
<span class="custom-icon">{{ $iconSvg | safeHTML }}</span>
{{ else }}
<span class="custom-icon">
<svg width="{{ $iconsize }}" height="{{ $iconsize }}" viewBox="0 0 24 24" fill="currentColor">
<path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
</svg>
</span>
{{ end }}
{{ else }}
<span class="custom-icon">
<svg width="{{ $iconsize }}" height="{{ $iconsize }}" viewBox="0 0 24 24" fill="currentColor">
<path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
</svg>
</span>
{{ end }}
</span>
{{ end }}
<span class="info-card-title">{{ $title }}</span>
</div>
<div class="info-card-right-section">
{{ if $tag }}
<span class="info-card-tag info-card-tag-{{ $tagtype }}">
{{ $tag }}
</span>
{{ end }}

{{ if $desc }}
<div class="info-card-tooltip-wrapper">
<span class="info-card-icon">
<svg class="info-icon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm0 13A6 6 0 1 1 8 2a6 6 0 0 1 0 12z"/>
<path d="M7 11h2v2H7zm0-8h2v6H7z"/>
</svg>
</span>
<div class="info-card-tooltip">
<div class="tooltip-description">{{ $desc | safeHTML }}</div>
{{ if or $date $audience }}
<div class="tooltip-details">
{{ if $date }}
<div class="tooltip-row">
<svg class="tooltip-row-icon" width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"/>
</svg>
<span class="tooltip-row-text">Добавлено: {{ $date }}</span>
</div>
{{ end }}
{{ if $audience }}
<div class="tooltip-row">
<svg class="tooltip-row-icon" width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/>
</svg>
<span class="tooltip-row-text">Для кого: {{ $audience }}</span>
</div>
{{ end }}
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
</a>
</div>

<style>
/* Основные стили */
.info-card {
margin: 0.75rem 0;
border: 1px solid #e0e0e0;
border-radius: 8px;
background: #ffffff;
transition: all 0.2s ease;
position: relative;
}

.info-card:hover {
border-color: #4a90e2;
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
}

.info-card-link {
display: block;
padding: 1rem 1.25rem;
text-decoration: none;
color: #333333;
}

.info-card-link:hover {
text-decoration: none;
}

.info-card-header {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 24px;
}

/* Левая часть */
.info-card-left {
display: flex;
align-items: center;
flex: 1;
padding-right: 12px;
min-height: 24px;
gap: 10px;
}

.info-card-title-icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}

.info-card-title-icon .custom-icon {
display: inline-flex;
align-items: center;
justify-content: center;
line-height: 0;
}

.info-card-title-icon .custom-icon svg {
width: 100%;
height: 100%;
fill: currentColor;
color: #666666;
vertical-align: middle;
}

.info-card-title {
font-size: 1rem;
font-weight: 600;
color: #333333;
line-height: 1.4;
flex: 1;
}

/* Правая часть */
.info-card-right-section {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}

/* Теги */
.info-card-tag {
font-size: 0.75rem;
padding: 0.15rem 0.5rem;
border-radius: 10px;
font-weight: 500;
white-space: nowrap;
border: 1px solid transparent;
}

.info-card-tag-default { background: #f0f0f0; color: #666666; border-color: #ddd; }
.info-card-tag-info { background: #e3f2fd; color: #1565c0; border-color: #90caf9; }
.info-card-tag-warning { background: #fff3e0; color: #e65100; border-color: #ffcc80; }
.info-card-tag-success { background: #e8f5e9; color: #2e7d32; border-color: #a5d6a7; }
.info-card-tag-error { background: #ffebee; color: #c62828; border-color: #ef9a9a; }

/* Иконка и тултип */
.info-card-tooltip-wrapper {
position: relative;
display: flex;
align-items: center;
}

.info-card-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
cursor: help;
color: #666666;
border-radius: 50%;
transition: all 0.15s;
}

.info-card-icon:hover {
background: #f0f0f0;
color: #4a90e2;
}

.info-icon {
width: 16px;
height: 16px;
}

/* Всплывающая подсказка - базовая позиция сверху */
.info-card-tooltip {
position: absolute;
bottom: calc(100% + 10px);
right: 50%;
transform: translateX(50%);
width: 420px;
max-width: 90vw;
padding: 18px;
background: white;
border-radius: 8px;
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
border: 1px solid #e0e0e0;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}

/* Альтернативная позиция - снизу (будет применяться через JS при необходимости) */
.info-card-tooltip.tooltip-bottom {
bottom: auto;
top: calc(100% + 10px);
transform: translateX(50%);
}

.info-card-tooltip-wrapper:hover .info-card-tooltip {
opacity: 1;
visibility: visible;
pointer-events: auto;
transform: translateX(50%) translateY(-5px);
}

.info-card-tooltip.tooltip-bottom:hover {
transform: translateX(50%) translateY(5px);
}

/* Стрелка тултипа - для позиции сверху */
.info-card-tooltip::before {
content: '';
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%) rotate(45deg);
width: 14px;
height: 14px;
background: white;
border-right: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
z-index: -1;
}

/* Стрелка для позиции снизу */
.info-card-tooltip.tooltip-bottom::before {
bottom: auto;
top: -7px;
transform: translateX(-50%) rotate(-135deg);
}

.tooltip-description {
font-size: 0.92rem;
line-height: 1.6;
color: #444444;
margin-bottom: 14px;
max-height: 250px;
overflow-y: auto;
padding-right: 6px;
}

.tooltip-description::-webkit-scrollbar { width: 6px; }
.tooltip-description::-webkit-scrollbar-track { background: #f5f5f5; border-radius: 3px; }
.tooltip-description::-webkit-scrollbar-thumb { background: #b0b0b0; border-radius: 3px; }

/* HTML в описании */
.tooltip-description p { margin: 0 0 10px 0; }
.tooltip-description p:last-child { margin-bottom: 0; }
.tooltip-description br { margin-bottom: 6px; }
.tooltip-description strong, .tooltip-description b { font-weight: 700; color: #333; }
.tooltip-description em, .tooltip-description i { font-style: italic; }
.tooltip-description u { text-decoration: underline; }
.tooltip-description code { background: #f7f7f7; padding: 3px 6px; border-radius: 4px; font-family: monospace; font-size: 0.88em; border: 1px solid #e0e0e0; }
.tooltip-description pre { background: #f7f7f7; padding: 12px; border-radius: 6px; overflow-x: auto; margin: 10px 0; font-size: 0.88em; border: 1px solid #e0e0e0; line-height: 1.5; }
.tooltip-description ul, .tooltip-description ol { margin: 10px 0; padding-left: 24px; }
.tooltip-description li { margin-bottom: 6px; line-height: 1.5; }
.tooltip-description a { color: #4a90e2; text-decoration: none; border-bottom: 1px dotted #4a90e2; }
.tooltip-description a:hover { text-decoration: none; border-bottom: 1px solid #4a90e2; color: #357abd; }

.tooltip-details {
font-size: 0.85rem;
color: #666666;
border-top: 1px solid #f0f0f0;
padding-top: 12px;
}

/* ФИКС ВЫРАВНИВАНИЯ ИКОНОК */
.tooltip-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}

.tooltip-row:last-child {
margin-bottom: 0;
}

.tooltip-row-icon {
flex-shrink: 0;
width: 14px;
height: 14px;
display: flex;
align-items: center;
justify-content: center;
}

.tooltip-row-text {
line-height: 1.4;
flex: 1;
display: flex;
align-items: center;
min-height: 20px;
}

/* Темная тема */
body.dark .info-card,
html.dark .info-card {
background: #2d3748;
border-color: #4a5568;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

body.dark .info-card:hover,
html.dark .info-card:hover {
border-color: #63b3ed;
box-shadow: 0 2px 8px rgba(99, 179, 237, 0.2);
}

body.dark .info-card-link,
html.dark .info-card-link {
color: #e2e8f0;
}

body.dark .info-card-title,
html.dark .info-card-title {
color: #f7fafc;
}

body.dark .info-card-title-icon .custom-icon svg {
color: #a0aec0;
}

body.dark .info-card-icon,
html.dark .info-card-icon {
color: #a0aec0;
}

body.dark .info-card-icon:hover,
html.dark .info-card-icon:hover {
background: #4a5568;
color: #63b3ed;
}

body.dark .info-card-tooltip,
html.dark .info-card-tooltip {
background: #1a202c;
border-color: #4a5568;
box-shadow: 0 5px 25px rgba(0,0,0,0.5);
}

body.dark .info-card-tooltip::before,
html.dark .info-card-tooltip::before {
background: #1a202c;
border-color: #4a5568;
}

body.dark .tooltip-description,
html.dark .tooltip-description {
color: #e2e8f0;
}

body.dark .tooltip-description strong,
body.dark .tooltip-description b,
html.dark .tooltip-description strong,
html.dark .tooltip-description b {
color: #f7fafc;
}

body.dark .tooltip-description code,
html.dark .tooltip-description code {
background: #2d3748;
color: #e2e8f0;
border: 1px solid #4a5568;
}

body.dark .tooltip-description pre,
html.dark .tooltip-description pre {
background: #2d3748;
border: 1px solid #4a5568;
color: #e2e8f0;
}

body.dark .tooltip-description a,
html.dark .tooltip-description a {
color: #63b3ed;
border-bottom-color: #63b3ed;
}

body.dark .tooltip-details,
html.dark .tooltip-details {
color: #a0aec0;
border-top-color: #4a5568;
}

body.dark .info-card-tag-default,
html.dark .info-card-tag-default {
background: #4a5568;
color: #cbd5e0;
border-color: #718096;
}

body.dark .info-card-tag-info,
html.dark .info-card-tag-info {
background: #2c5282;
color: #bee3f8;
border-color: #3182ce;
}

body.dark .info-card-tag-warning,
html.dark .info-card-tag-warning {
background: #975a16;
color: #feebc8;
border-color: #d69e2e;
}

body.dark .info-card-tag-success,
html.dark .info-card-tag-success {
background: #276749;
color: #c6f6d5;
border-color: #38a169;
}

body.dark .info-card-tag-error,
html.dark .info-card-tag-error {
background: #9b2c2c;
color: #fed7d7;
border-color: #e53e3e;
}

/* Адаптивность */
@media (max-width: 768px) {
.info-card-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}

.info-card-left {
width: 100%;
padding-right: 0;
}

.info-card-right-section {
width: 100%;
justify-content: space-between;
}

.info-card-tooltip {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) !important;
width: calc(100vw - 40px);
max-width: 500px;
max-height: 70vh;
overflow-y: auto;
bottom: auto !important;
right: auto !important;
}

.info-card-tooltip::before {
display: none;
}

.info-card {
margin: 0.5rem 0;
}

.info-card-link {
padding: 0.75rem 1rem;
}

.tooltip-description {
max-height: 40vh;
font-size: 0.9rem;
}

.tooltip-row {
align-items: center;
}

.tooltip-row-text {
min-height: 18px;
}
}

@media (max-width: 480px) {
.info-card-tooltip {
width: calc(100vw - 20px);
padding: 14px;
}

.tooltip-description {
font-size: 0.88rem;
}

.tooltip-details {
font-size: 0.82rem;
}

.info-card-left {
gap: 8px;
}
}

@media (min-width: 1200px) {
.info-card-tooltip {
width: 450px;
}
}

@media (min-width: 1400px) {
.info-card-tooltip {
width: 480px;
}
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
// Простая инициализация тултипов с умным позиционированием
const wrappers = document.querySelectorAll('.info-card-tooltip-wrapper');

wrappers.forEach(wrapper => {
const tooltip = wrapper.querySelector('.info-card-tooltip');
const icon = wrapper.querySelector('.info-card-icon');

if (!tooltip || !icon) return;

// Функция для определения лучшей позиции
function adjustTooltipPosition() {
if (window.innerWidth <= 768) return; // На мобильных не меняем

const wrapperRect = wrapper.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const viewportHeight = window.innerHeight;

// Вычисляем доступное пространство сверху и снизу
const spaceAbove = wrapperRect.top;
const spaceBelow = viewportHeight - wrapperRect.bottom;
const tooltipHeight = tooltipRect.height;

// Если сверху мало места для тултипа, показываем снизу
if (spaceAbove < tooltipHeight + 20 && spaceBelow >= tooltipHeight + 20) {
tooltip.classList.add('tooltip-bottom');
} else {
tooltip.classList.remove('tooltip-bottom');
}
}

wrapper.addEventListener('mouseenter', function() {
adjustTooltipPosition();
tooltip.style.opacity = '1';
tooltip.style.visibility = 'visible';
});

wrapper.addEventListener('mouseleave', function() {
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
});

wrapper.addEventListener('click', function(e) {
if (window.innerWidth <= 768) {
e.preventDefault();
e.stopPropagation();

if (tooltip.style.opacity === '1') {
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
} else {
tooltip.style.opacity = '1';
tooltip.style.visibility = 'visible';
}
}
});
});

// Перепозиционирование при скролле
let scrollTimer;
window.addEventListener('scroll', function() {
clearTimeout(scrollTimer);
scrollTimer = setTimeout(function() {
document.querySelectorAll('.info-card-tooltip-wrapper').forEach(wrapper => {
const tooltip = wrapper.querySelector('.info-card-tooltip');
if (tooltip && tooltip.style.opacity === '1') {
// Просто переключаем класс для перепозиционирования
const isBottom = tooltip.classList.contains('tooltip-bottom');
tooltip.classList.remove('tooltip-bottom');
setTimeout(() => {
const wrapperRect = wrapper.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const viewportHeight = window.innerHeight;
const spaceAbove = wrapperRect.top;
const spaceBelow = viewportHeight - wrapperRect.bottom;

if (spaceAbove < tooltipRect.height + 20 && spaceBelow >= tooltipRect.height + 20) {
tooltip.classList.add('tooltip-bottom');
}
}, 10);
}
});
}, 50);
});

// Перепозиционирование при изменении размера окна
window.addEventListener('resize', function() {
document.querySelectorAll('.info-card-tooltip-wrapper').forEach(wrapper => {
const tooltip = wrapper.querySelector('.info-card-tooltip');
if (tooltip && tooltip.style.opacity === '1') {
// Сбросим и заново применим позиционирование
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.opacity = '1';
}, 10);
}
});
});

// Закрытие тултипов при клике вне
document.addEventListener('click', function(e) {
if (!e.target.closest('.info-card-tooltip-wrapper')) {
document.querySelectorAll('.info-card-tooltip').forEach(tooltip => {
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
});
}
});

// Закрытие по ESC
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
document.querySelectorAll('.info-card-tooltip').forEach(tooltip => {
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
});
}
});
});
</script>

Добавлено (2026-01-14, 13:43)
---------------------------------------------
https://github.com/gohugoio/hugo/releases?page=2

{{- $link := .Get "link" -}}
{{- $title := .Get "title" -}}
{{- $iconName := .Get "icon" -}}
{{- $subtitle := .Get "subtitle" -}}
{{- $image := .Get "image" -}}
{{- $width := 0 -}}
{{- $height := 0 -}}
{{- $imageStyle := .Get "imageStyle" -}}
{{- $tag := .Get "tag" -}}
{{- $tagType := .Get "tagType" -}}

{{/* Image processing options */}}
{{- $method := .Get "method" | default "Resize" | humanize -}}
{{- $options := .Get "options" | default "800x webp q80" -}}
{{- $process := .Get "process" | default (printf "%s %s" $method $options) -}}

{{- if and $image (not (urls.Parse $image).Scheme) -}}
{{- with or (.Page.Resources.Get $image) (resources.Get $image) -}}
{{/* .Process does not work on svgs */}}
{{- if (not (eq .MediaType.SubType "svg")) -}}
{{/* Retrieve the $image resource from local or global resources */}}
{{- $processed := .Process $process -}}
{{- $width = $processed.Width -}}
{{- $height = $processed.Height -}}
{{- $image = $processed.RelPermalink -}}
{{- end -}}
{{ else }}
{{/* Otherwise, use relative link of the image */}}
{{- if hasPrefix $image "/" -}}
{{- $image = relURL (strings.TrimPrefix "/" $image) -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/* ========== НОВЫЙ КОД ДЛЯ ИКОНОК НА ОСНОВЕ cardinfo.html ========== */}}
{{- $icon := "" -}}
{{- if $iconName -}}
{{/* Используем тот же подход, что и в cardinfo.html */}}
{{- if .Site.Data.icons -}}
{{- $iconData := index .Site.Data.icons $iconName -}}
{{- if $iconData -}}
{{- $iconSvg := replaceRE "<svg" "<svg width='24' height='24'" $iconData -}}
{{- $icon = $iconSvg | safeHTML -}}
{{- else -}}
{{/* Fallback иконка, как в cardinfo.html */}}
{{- $icon = "<svg width='24' height='24' viewBox='0 0 24 24' fill='currentColor'><path d='M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z'/></svg>" | safeHTML -}}
{{- warnf "Иконка '%s' не найдена в .Site.Data.icons" $iconName -}}
{{- end -}}
{{- else -}}
{{/* Если .Site.Data.icons не существует */}}
{{- $icon = "<svg width='24' height='24' viewBox='0 0 24 24' fill='currentColor'><path d='M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z'/></svg>" | safeHTML -}}
{{- warnf ".Site.Data.icons не существует. Иконка: '%s'" $iconName -}}
{{- end -}}
{{- end -}}
{{/* ========== КОНЕЦ НОВОГО КОДА ========== */}}

{{- partial "shortcodes/card" (dict
"page" .Page
"link" $link
"title" $title
"icon" $icon
"subtitle" $subtitle
"image" $image
"width" $width
"height" $height
"imageStyle" $imageStyle
"tag" $tag
"tagType" $tagType
)
-}}
hugo server
Watching for changes in Z:\GDB\HUGO_SITE\hugo\example\{archetypes,assets,content,data,i18n,layouts,postcss.config.js,static,tailwind.config.js}
Watching for config changes in Z:\GDB\HUGO_SITE\hugo\example\hugo.yaml
Start building sites …
hugo v0.152.0-06bc2c16c0c0bbff7e662fbeef7ead6f9c55ea0d+extended windows/amd64 BuildDate=2025-10-21T16:29:49Z VendorInfo=gohugoio

ERROR icon "document-text" not found
ERROR icon "folder" not found
ERROR icon "folder-open" not found
ERROR failed to load data: failed to load data: "Z:\GDB\HUGO_SITE\hugo\example\data\icon_descriptions.yaml:334:1": [334:1] mapping key "key" already defined at [159:1]
331 | data_ex: "Обмен данными"
332 | manual: "Список классификаторов"
333 | settings: "Настройки"
> 334 | key: ""
^
335 | table: ""
336 | admin: ""
337 | carman: "Карман"
ERROR icon "hamburger-menu" not found
ERROR icon "sun" not found
ERROR icon "moon" not found
ERROR icon "chevron-right" not found
ERROR icon "refresh" not found
ERROR icon "edit" not found
ERROR icon "check" not found
ERROR icon "cancel" not found
ERROR icon "plus" not found
ERROR icon "copy" not found
ERROR icon "eraser" not found
ERROR icon "x" not found
ERROR icon "search" not found
ERROR icon "document-add" not found
ERROR icon "exit_add" not found
ERROR icon "exit_w" not found
ERROR icon "document-search" not found
ERROR icon "poverki" not found
ERROR icon "xy_card" not found
ERROR icon "coord_list" not found
ERROR icon "info" not found
ERROR icon "h" not found
ERROR icon "settings_form" not found
ERROR icon "spravochnik" not found
ERROR icon "add_before" not found
ERROR icon "struct_doc_add" not found
ERROR icon "struct_doc_text" not found
ERROR icon "struct_doc_del" not found
ERROR icon "save" not found
ERROR icon "exit_soft" not found
ERROR icon "light-bulb" not found
ERROR icon "information-circle" not found
ERROR icon "exclamation-circle" not found
ERROR icon "prv_vin" not found
ERROR icon "coord_format_grad" not found
ERROR icon "coord_view_list" not found
ERROR icon "add_tn_to_rizhim_set" not found
ERROR icon "del_tn_to_rizhim_set" not found
ERROR icon "geology" not found
ERROR icon "geophiz" not found
ERROR icon "hydro" not found
ERROR icon "beaker" not found
ERROR icon "tn" not found
ERROR icon "blocks_list" not found
ERROR icon "work" not found
ERROR icon "catalog_confirm" not found
ERROR icon "add_lab_card" not found
ERROR icon "del_lab_card" not found
ERROR icon "add_cart_min" not found
ERROR icon "carman" not found
ERROR icon "confirm_reg" not found
ERROR icon "exclamation" not found
ERROR icon "samples_go" not found
ERROR icon "download" not found
ERROR icon "samples" not found
ERROR icon "wk" not found
ERROR icon "ruler" not found
ERROR icon "add_interval_dril" not found
ERROR icon "number_list" not found
ERROR icon "import_chemelem" not found
ERROR icon "arrow-sm-right" not found
ERROR icon "import_RSA" not found
ERROR icon "catalogs" not found
ERROR icon "add_proba" not found
ERROR icon "catalog_go" not found
ERROR icon "working_add" not found
ERROR icon "perenos_gis" not found
ERROR icon "add_zamer" not found
ERROR icon "bufer_add" not found
ERROR icon "photo-view" not found
ERROR icon "photo-view-list" not found
ERROR icon "photo-preview-window" not found
ERROR icon "mineralogy" not found
ERROR icon "geochem" not found
ERROR icon "microzond" not found
ERROR icon "petrography" not found
ERROR icon "petrophiz" not found
ERROR icon "mesto" not found
ERROR icon "add_cart_petrograph" not found
ERROR icon "add_group_prob_petro" not found
ERROR icon "export" not found
ERROR icon "settings_window" not found
ERROR icon "add_cart_petro" not found
ERROR icon "import_petrofiz" not found
ERROR icon "sort-ascending" not found
ERROR icon "cancel_reg_work" not found
ERROR icon "import_las" not found
ERROR icon "diamond" not found
ERROR icon "not_almaz" not found
ERROR icon "set_almaz" not found
ERROR icon "arrow_up" not found
ERROR icon "arrow_down" not found
ERROR icon "tyazh_min" not found
ERROR icon "filter" not found
ERROR icon "filter_col_del" not found
ERROR icon "filter_cols_del" not found
ERROR icon "sl_las" not found
ERROR icon "export_las" not found
ERROR icon "avariya" not found
ERROR icon "carman_open" not found
ERROR icon "c_down" not found
ERROR icon "c_up" not found
ERROR icon "c_ddown" not found
ERROR icon "c_dup" not found
ERROR icon "isihogi_icon" not found
ERROR icon "help_book" not found
ERROR icon "rvgi" not found
ERROR icon "admin" not found
ERROR icon "book-open" not found
ERROR icon "tool" not found
ERROR icon "globe-alt" not found
ERROR icon "clipboard-check" not found
Built in 106594 ms

Change detected, rebuilding site (#1).
2026-01-14 13:50:22.115 +0700
Source changed /docs/manuals/geology/assays/utochnenie.md
Data changed /icon_descriptions.yaml
ERROR icon "edit" not found
ERROR icon "plus" not found
ERROR icon "copy" not found
ERROR icon "check" not found
ERROR icon "exclamation-circle" not found
ERROR icon "hamburger-menu" not found
ERROR icon "sun" not found
ERROR icon "moon" not found
ERROR icon "chevron-right" not found
ERROR failed to load data: failed to load data: "Z:\GDB\HUGO_SITE\hugo\example\data\icon_descriptions.yaml:334:1": [334:1] mapping key "key" already defined at [159:1]
331 | data_ex: "Обмен данными"
332 | manual: "Список классификаторов"
333 | settings: "Настройки"
> 334 | key: ""
^
335 | table: ""
336 | admin: ""
337 | carman: "Карман"
ERROR Rebuild failed: failed to load data: "Z:\GDB\HUGO_SITE\hugo\example\data\icon_descriptions.yaml:334:1": [334:1] mapping key "key" already defined at [159:1]
331 | data_ex: "Обмен данными"
332 | manual: "Список классификаторов"
333 | settings: "Настройки"
> 334 | key: ""
^
335 | table: ""
336 | admin: ""
337 | carman: "Карман"
Web Server is available at http://localhost:1313/hugo/ (bind address 127.0.0.1)
Total in 51 ms
Error: error building site: failed to load data: failed to load data: "Z:\GDB\HUGO_SITE\hugo\example\data\icon_descriptions.yaml:334:1": [334:1] mapping key "key" already defined at [159:1]
331 | data_ex: "Обмен данными"
332 | manual: "Список классификаторов"
333 | settings: "Настройки"
> 334 | key: ""
^
335 | table: ""
336 | admin: ""
337 | carman: "Карман"
Давайте проанализирую ваш процесс сборки и сравним с оптимальным workflow.

🔍 Анализ вашего текущего процесса

Вы делаете:

1. hugo server (для разработки)
2. Берете папку public/ после работы
3. Заливаете на хостинг

Что не так с этим подходом:

Аспект Ваш способ Оптимальный способ
Сборка Собирается сервером для dev Специальная prod-сборка
Минификация Нет (dev-сборка) Да (уменьшение размера)
Кеширование Проблемы с кешем Версионирование файлов
Производительность Неоптимизировано Оптимизировано
Отладка Dev-код в продакшене Minified в продакшене

🚀 Правильный процесс сборки

Этап 1: Разработка (как вы делаете)

```bash
hugo server -D # С флагом -D если есть черновики
```

✅ Правильно - так и нужно делать для разработки.

Этап 2: Продакшн-сборка (чего не хватает)

```bash
# ВАЖНО: Останавливаем hugo server (Ctrl+C) перед этой командой!

# Базовая продакшн-сборка
hugo --minify

# Или расширенная
hugo --minify --cleanDestinationDir --gc --enableGitInfo
```

Что дают эти флаги:

· --minify - минифицирует HTML, CSS, JS
· --cleanDestinationDir - удаляет старые файлы из public/
· --gc - сборка мусора (уменьшает размер)
· --enableGitInfo - добавляет git-информацию

Этап 3: Проверка сборки

```bash
# После сборки проверьте
hugo check # Проверка ошибок

# Посмотреть что собралось
ls -la public/ # Linux/Mac
dir public # Windows
```

📊 Сравнение размеров

Пример для типичного сайта:

```
Ваш способ (dev-сборка):
- CSS: 150KB (не минифицированный)
- JS: 200KB (не минифицированный)
- HTML: с отступами и комментариями

Правильный способ (prod-сборка):
- CSS: 50KB (-66%)
- JS: 80KB (-60%)
- HTML: компактный (-40%)
```

🛠️ Оптимизированный workflow

Создайте скрипты для автоматизации:

1. Для Windows (build-prod.bat):

```batch
@echo off
echo [1/4] Остановка dev-сервера...
taskkill /F /IM hugo.exe 2>nul

echo [2/4] Очистка предыдущей сборки...
if exist public rmdir /s /q public

echo [3/4] Продакшн-сборка...
hugo --minify --cleanDestinationDir --gc

echo [4/4] Проверка...
echo ============ ИТОГИ ============
dir public /s | find "Файл"
echo ================================
echo Сборка завершена! Папка 'public' готова.
pause
```

2. Для Linux/Mac (build-prod.sh):

```bash
#!/bin/bash
echo "🚀 Продакшн-сборка Hugo"

# Останавливаем dev-сервер если запущен
pkill -f "hugo server" 2>/dev/null

# Очистка
rm -rf public

# Сборка
hugo --minify --cleanDestinationDir --gc

# Проверка
echo "✅ Собрано:"
du -sh public/
find public -type f -name "*.html" | head -5
```

🔧 Дополнительные оптимизации

Добавьте в hugo.yaml:

```yaml
# hugo.yaml
build:
writeStats: true # Для анализа сборки
useResourceCacheWhen: never # Всегда пересобирать ресурсы

minify:
minifyOutput: true
tdewolff:
html:
keepWhitespace: false
css:
keepCSS2: false
js:
keepVarNames: false
```

Для обработки ресурсов (CSS/JS/images):

```go-html-template
<!-- В шаблонах вместо -->
<link rel="stylesheet" href="/css/style.css">

<!-- Используйте -->
{{ $css := resources.Get "css/style.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}">
```

📋 Чек-лист правильной сборки

Перед заливкой на хостинг убедитесь:

· Остановлен hugo server (Ctrl+C)
· Использована команда hugo --minify
· Проверены CSS/JS - они минифицированы (одна строка)
· В HTML нет лишних пробелов/комментариев
· Все изображения оптимизированы
· В public/ только нужные файлы
· Размер public/ адекватный (обычно 1-20MB)

⚡ Быстрая команда для вас

Просто запомните:

```bash
# Когда закончили разработку:
1. Ctrl+C (остановить hugo server)
2. hugo --minify
3. Залить папку public/ на хостинг
```

🎯 Итог

Вы делаете на 80% правильно, но не хватает продакшн-оптимизаций. Разница между dev и prod сборкой:

· Dev (hugo server) - для разработки, быстрая пересборка
· Prod (hugo --minify) - для хостинга, оптимизированная

Исправление простое: всегда используйте hugo --minify перед заливкой на хостинг, и проблема с кешем решится через версионирование файлов (как обсуждали ранее).

Попробуйте собрать проект с --minify и сравните размеры и содержимое файлов в public/ - увидите разницу сразу!
Отлично! Вот два батника для полного цикла работы с Hugo.

🚀 start-dev.bat - Запуск сервера для разработки

```batch
@echo off
echo ========================================
echo Hugo Dev Server Launcher
echo ========================================
echo.

REM Проверяем, не запущен ли уже сервер
tasklist /FI "IMAGENAME eq hugo.exe" 2>NUL | find /I /N "hugo.exe">NUL
if "%ERRORLEVEL%"=="0" (
echo [ОШИБКА] Hugo сервер уже запущен!
echo Остановите его командой: Ctrl+C в том окне
echo или используйте: stop-server.bat
echo.
pause
exit /b 1
)

REM Проверяем наличие hugo
where hugo >nul 2>nul
if errorlevel 1 (
echo [ОШИБКА] Hugo не найден!
echo Установите Hugo или добавьте в PATH
echo.
pause
exit /b 1
)

REM Очистка старой сборки если есть
if exist public (
echo [INFO] Удаляю старую папку public...
rmdir /s /q public >nul 2>nul
)

echo [1/3] Запуск Hugo в режиме разработки...
echo [INFO] Сайт будет доступен: http://localhost:1313
echo [INFO] Для остановки: Ctrl+C в этом окне
echo.

REM Запуск с нужными параметрами
echo ========================================
echo НАЧАЛО ВЫВОДА HUGO
echo ========================================
echo.

hugo server -D --disableFastRender --navigateToChanged

REM Если hugo завершился с ошибкой
if errorlevel 1 (
echo.
echo ========================================
echo [ОШИБКА] Hugo завершился с кодом %ERRORLEVEL%
echo Проверьте конфигурацию и шаблоны
echo ========================================
pause
)
```

📦 build-prod.bat - Продакшн сборка

```batch
@echo off
echo ========================================
echo Hugo Production Builder v1.0
echo ========================================
echo.

REM Проверяем наличие hugo
where hugo >nul 2>nul
if errorlevel 1 (
echo [ОШИБКА] Hugo не найден!
echo Установите Hugo или добавьте в PATH
echo.
pause
exit /b 1
)

REM Останавливаем dev сервер если запущен
echo [1/5] Проверка запущенных Hugo процессов...
tasklist /FI "IMAGENAME eq hugo.exe" 2>NUL | find /I /N "hugo.exe">NUL
if "%ERRORLEVEL%"=="0" (
echo [WARNING] Обнаружен запущенный Hugo сервер
choice /M "Остановить его"
if errorlevel 2 (
echo [INFO] Продолжаю без остановки...
) else (
echo [INFO] Останавливаю Hugo сервер...
taskkill /F /IM hugo.exe >nul 2>nul
timeout /t 2 /nobreak >nul
)
)

REM Очистка
echo [2/5] Очистка предыдущей сборки...
if exist public (
rmdir /s /q public >nul 2>nul
echo [OK] Папка public удалена
) else (
echo [OK] Папка public не найдена (чистая сборка)
)

REM Сборка
echo [3/5] Продакшн-сборка Hugo...
echo [INFO] Параметры: --minify --cleanDestinationDir --gc
echo.

hugo --minify --cleanDestinationDir --gc

if errorlevel 1 (
echo.
echo ========================================
echo [ОШИБКА] Сборка не удалась!
echo Проверьте ошибки выше
echo ========================================
pause
exit /b 1
)

REM Проверка результатов
echo [4/5] Проверка результатов сборки...
if not exist public (
echo [ОШИБКА] Папка public не создана!
pause
exit /b 1
)

REM Показываем статистику
echo [5/5] Анализ сборки...
echo ========================================
echo СТАТИСТИКА СБОРКИ
echo ========================================

REM Считаем файлы
setlocal enabledelayedexpansion
set /a html_count=0
set /a css_count=0
set /a js_count=0
set /a img_count=0
set /a total_count=0
set /a total_size=0

for /r public %%f in (*) do (
set /a total_count+=1
for %%s in (%%~zf) do set /a total_size+=%%s

if /i "%%~xf"==".html" set /a html_count+=1
if /i "%%~xf"==".css" set /a css_count+=1
if /i "%%~xf"==".js" set /a js_count+=1
if /i "%%~xf"==".jpg" set /a img_count+=1
if /i "%%~xf"==".png" set /a img_count+=1
if /i "%%~xf"==".svg" set /a img_count+=1
if /i "%%~xf"==".webp" set /a img_count+=1
)

set /a size_mb=!total_size!/1048576
set /a size_kb=!total_size!/1024

echo Файлов всего: !total_count!
echo HTML страниц: !html_count!
echo CSS файлов: !css_count!
echo JS файлов: !js_count!
echo Изображений: !img_count!
echo Размер сборки: !size_kb! KB (!size_mb! MB)
echo ========================================
echo.

REM Показываем созданные HTML файлы
echo Первые 10 HTML файлов:
dir /b /s public\*.html | head -10 2>nul
if errorlevel 1 (
dir /b /s public\*.html | more +1
)

echo.
echo ========================================
echo [УСПЕХ] Сборка завершена!
echo.
echo Действия:
echo 1. Проверить сайт локально (см. ниже)
echo 2. Залить ВСЁ содержимое папки 'public'
echo на хостинг в корневую директорию
echo.
echo Для локальной проверки запустите:
echo test-local.bat
echo ========================================
echo.

choice /M "Запустить локальную проверку"
if errorlevel 2 (
echo [INFO] Проверка отменена
echo Папка 'public' готова к загрузке на хостинг
) else (
call test-local.bat
)

pause
```

🔍 test-local.bat - Локальная проверка продакшн сборки

```batch
@echo off
echo ========================================
echo Local Production Test
echo ========================================
echo.

if not exist public (
echo [ОШИБКА] Папка public не найдена!
echo Сначала выполните build-prod.bat
echo.
pause
exit /b 1
)

echo [INFO] Запуск локального сервера для тестирования...
echo [INFO] Сайт будет доступен: http://localhost:8080
echo [INFO] Для остановки: Ctrl+C
echo.
echo ========================================
echo.

REM Проверяем наличие Python (самый простой сервер)
python --version >nul 2>nul
if errorlevel 1 (
echo [WARNING] Python не найден, использую PowerShell...
powershell -Command "cd public; \$listener = New-Object System.Net.HttpListener; \$listener.Prefixes.Add('http://localhost:8080/'); \$listener.Start(); Write-Host 'Сервер запущен на http://localhost:8080'; while (\$true) { \$context = \$listener.GetContext(); \$content = [System.IO.File]::ReadAllText('public' + \$context.Request.RawUrl.Replace('/', '\')); \$buffer = [System.Text.Encoding]::UTF8.GetBytes(\$content); \$context.Response.ContentLength64 = \$buffer.Length; \$context.Response.OutputStream.Write(\$buffer, 0, \$buffer.Length); \$context.Response.Close() }"
) else (
echo [INFO] Запуск через Python HTTP сервер...
cd public
python -m http.server 8080
)
```

🛑 stop-server.bat - Остановка сервера (опционально)

```batch
@echo off
echo ========================================
echo Hugo Server Stopper
echo ========================================
echo.

tasklist /FI "IMAGENAME eq hugo.exe" 2>NUL | find /I /N "hugo.exe">NUL
if "%ERRORLEVEL%"=="0" (
echo [INFO] Останавливаю Hugo сервер...
taskkill /F /IM hugo.exe >nul 2>nul
if errorlevel 1 (
echo [ОШИБКА] Не удалось остановить Hugo
) else (
echo [OK] Hugo сервер остановлен
)
) else (
echo [INFO] Hugo сервер не запущен
)

timeout /t 2 /nobreak >nul
echo.
pause
```

📁 Структура файлов

Создайте в корне проекта папку scripts и положите туда все батники:

```
ваш-проект/
├── scripts/
│ ├── start-dev.bat # Для разработки
│ ├── build-prod.bat # Продакшн сборка
│ ├── test-local.bat # Проверка сборки
│ └── stop-server.bat # Остановка сервера
├── content/
├── layouts/
├── public/ (создаётся автоматически)
└── hugo.yaml
```

🎯 Краткое руководство

1. Разработка:

```bash
scripts\start-dev.bat
# Сайт на http://localhost:1313
# Автоматическая пересборка при изменениях
```

2. Сборка для хостинга:

```bash
scripts\build-prod.bat
# Создаёт оптимизированную папку public/
```

3. Проверка перед заливкой:

```bash
scripts\test-local.bat
# Тестируем продакшн-сборку на http://localhost:8080
```

⚙️ Настройка под себя

Если хотите изменить порты, отредактируйте строки:

В start-dev.bat (строка ~35):

```batch
hugo server -D --disableFastRender --navigateToChanged --port 1313 --bind 127.0.0.1
```

В test-local.bat можно поменять порт 8080 на любой другой.

🔧 Если не работают Python/ PowerShell

Добавьте в test-local.bat альтернативный вариант:

```batch
REM После проверки Python добавьте:
echo [INFO] Альтернатива: откройте в браузере
echo file:///%cd%/public/index.html
echo.
echo Нажмите любую клавишу чтобы открыть...
pause >nul
start file:///%cd%/public/index.html
```

Теперь у вас полный набор скриптов для профессиональной работы с Hugo! 🚀
старая рабочая версия
Z:\HUGO_SITE\hugo\example>hugo server
Watching for changes in Z:\HUGO_SITE\hugo\example\{archetypes,assets,content,data,i18n,layouts,postcss.config.js,static,tailwind.config.js}
Watching for config changes in Z:\HUGO_SITE\hugo\example\hugo.yaml
Start building sites …
hugo v0.150.0-3f5473b7d4e7377e807290c3acc89feeef1aaa71+extended windows/amd64 BuildDate=2025-09-08T13:01:12Z VendorInfo=gohugoio

а вот новая и с ней некоторые страницы не грузятся висят на загрузке
Z:\HUGO_SITE\hugo\example>hugo server
Watching for changes in Z:/HUGO_SITE/hugo/example/archetypes, Z:/HUGO_SITE/hugo/example/assets/{css,images,js,json,lib}, Z:/HUGO_SITE/hugo/example/content/{about,certificate,docs,downloads,fonts,...}, Z:/HUGO_SITE/hugo/example/data, Z:/HUGO_SITE/hugo/example/i18n, Z:/HUGO_SITE/hugo/example/layouts/{_default,blog,docs,icons,partials,...}, Z:/HUGO_SITE/hugo/example/postcss.config.js, Z:/HUGO_SITE/hugo/example/static/images, Z:/HUGO_SITE/hugo/example/tailwind.config.js
Watching for config changes in Z:\HUGO_SITE\hugo\example\hugo.yaml
Start building sites …
hugo v0.154.5-a6f99cca223a29cad1d4cdaa6a1a90508ac1da71+extended windows/amd64 BuildDate=2026-01-11T20:53:23Z VendorInfo=gohugoio
  • Страница 3 из 3
  • «
  • 1
  • 2
  • 3
Поиск:
Новый ответ
Имя:
Текст сообщения: