Files
ave-cms/adminx/modules/Media/view/file.twig
T
2026-07-30 16:34:14 +03:00

164 lines
11 KiB
Twig
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends '@adminx/main.twig' %}
{% block title %}{{ file.name }}{% endblock %}
{% block content %}
<nav class="breadcrumbs" aria-label="Хлебные крошки">
<a href="{{ ADMINX_BASE }}/">Главная</a><i class="ti ti-chevron-right"></i>
<a href="{{ ADMINX_BASE }}/media?dir={{ parent_dir|url_encode }}">Медиа</a><i class="ti ti-chevron-right"></i>
<span>{{ file.name }}</span>
</nav>
<div class="page-header">
<div class="between">
<div>
<h1>{{ file.name }}</h1>
<p class="text-secondary mono" style="margin-top:5px">{{ file.path }}</p>
</div>
<div class="cluster">
<a class="btn btn-secondary" href="{{ ADMINX_BASE }}/media?dir={{ parent_dir|url_encode }}"><i class="ti ti-arrow-left"></i>К списку</a>
<a class="btn btn-secondary" href="{{ file.url }}" target="_blank" rel="noopener"><i class="ti ti-external-link"></i>Открыть</a>
<button class="btn btn-secondary" type="button" data-copy="{{ file.path }}"><i class="ti ti-copy"></i>Путь</button>
</div>
</div>
</div>
<div class="media-file-layout" data-media-editor>
<section class="card media-preview-card">
<div class="media-section-head">
<div class="media-section-title">
<span class="icon-tile media-head-icon" style="--tile-bg:#ecfdf3;--tile-fg:#16a34a"><i class="ti ti-photo-cog"></i></span>
<div>
<h2>Предпросмотр</h2>
<p class="text-secondary">{{ file.meta ?: file.extension }}</p>
</div>
</div>
<span class="badge {{ file.is_image ? 'badge-green' : 'badge-blue' }}">{{ file.is_image ? 'Изображение' : 'Файл' }}</span>
</div>
<div class="media-preview-stage">
{% if file.is_image %}
<div class="media-crop-frame" data-crop-frame>
<img src="{{ file.url }}" alt="" data-crop-image>
{% if file.extension != 'svg' and can_manage %}
<div class="media-crop-box" data-crop-box>
<span class="media-crop-size" data-crop-size></span>
<span data-crop-handle="nw"></span><span data-crop-handle="ne"></span>
<span data-crop-handle="sw"></span><span data-crop-handle="se"></span>
</div>
{% endif %}
</div>
{% else %}
<div class="media-file-placeholder"><i class="ti ti-file"></i><b>{{ file.extension ?: 'file' }}</b></div>
{% endif %}
</div>
<div class="media-file-meta">
<span>Размер: <b>{{ file.size_label }}</b></span>
<span>Габариты: <b>{{ file.width and file.height ? file.width ~ 'x' ~ file.height : '-' }}</b></span>
<span>Изменён: <b>{{ file.mtime_label }}</b></span>
</div>
</section>
<aside class="card media-editor-card">
<div class="media-section-head">
<div class="media-section-title">
<span class="icon-tile media-head-icon" style="--tile-bg:#fff7ed;--tile-fg:#ea580c"><i class="ti ti-adjustments"></i></span>
<div>
<h2>Действия</h2>
<p class="text-secondary">Переименование, удаление и редактор изображения.</p>
</div>
</div>
</div>
{% if can_manage %}
<div class="media-tool-group">
<button class="btn btn-secondary" type="button" data-media-rename data-path="{{ file.path }}" data-name="{{ file.name }}" data-kind="file"><i class="ti ti-pencil"></i>Переименовать</button>
<button class="btn btn-danger-soft" type="button" data-media-delete data-path="{{ file.path }}" data-name="{{ file.name }}" data-kind="file"><i class="ti ti-trash"></i>Удалить</button>
</div>
{% if file.is_image and file.extension != 'svg' %}
<form class="media-transform-form" method="post" action="{{ ADMINX_BASE }}/media/transform">
<input type="hidden" name="_csrf" value="{{ csrf_token }}">
<input type="hidden" name="path" value="{{ file.path }}">
<input type="hidden" name="crop_enabled" value="0" data-crop-enabled>
<input type="hidden" name="webp_twin" value="0" data-webp-twin>
<input type="hidden" name="crop_x" value="0" data-crop-input="x">
<input type="hidden" name="crop_y" value="0" data-crop-input="y">
<input type="hidden" name="crop_w" value="{{ file.width ?: 1 }}" data-crop-input="w">
<input type="hidden" name="crop_h" value="{{ file.height ?: 1 }}" data-crop-input="h">
<div class="media-result" data-media-result>
<div class="media-result-head"><span><i class="ti ti-photo-check"></i>Результат по настройкам</span><b class="media-result-meta" data-media-result-meta>—</b></div>
<button class="media-result-stage" type="button" data-media-result-zoom data-tooltip="Открыть крупно" aria-label="Открыть результат крупно"><img alt="Результат" data-media-result-img><span class="media-result-empty" data-media-result-empty>Меняйте настройки — результат обновится здесь</span></button>
</div>
{% if presets %}
<div class="media-preset-pick">
<label class="media-preset-pick-field"><span><i class="ti ti-aspect-ratio"></i> Подогнать под вид</span>
<select class="select" data-crop-preset>
<option value="">— вручную —</option>
{% for p in presets %}
<option value="{{ p.code }}" data-mode="{{ p.mode }}" data-width="{{ p.width }}" data-height="{{ p.height }}" data-format="{{ p.format }}" data-quality="{{ p.quality }}" data-webp-twin="{{ p.webp_twin }}">{{ p.label }}{% if p.webp_twin %} · +WebP{% endif %}</option>
{% endfor %}
</select>
</label>
<p class="media-preset-warn" data-crop-preset-warning hidden></p>
</div>
{% endif %}
<div class="media-form-grid">
<label><span>Кадр</span><select class="select" data-crop-ratio><option value="original">Оригинал</option><option value="free">Свободный</option><option value="1:1">1:1</option><option value="4:3">4:3</option><option value="16:9">16:9</option><option value="9:16">9:16</option></select></label>
<label><span>Режим</span><select class="select" name="mode"><option value="cover">Обрезать</option><option value="contain">Вписать</option><option value="fit">Уменьшить</option><option value="stretch">Растянуть</option></select></label>
<label><span>Ширина</span><input class="input" type="number" min="1" max="2400" name="width" value="{{ file.width ?: 320 }}"></label>
<label><span>Высота</span><input class="input" type="number" min="1" max="2400" name="height" value="{{ file.height ?: 240 }}"></label>
<label><span>Формат</span><select class="select" name="format"><option value="original">Оригинал</option><option value="jpg">JPG</option><option value="png">PNG</option>{% if supports_webp %}<option value="webp">WebP</option>{% endif %}</select></label>
<label><span>Качество</span><input class="input" type="number" min="1" max="100" name="quality" value="82"></label>
</div>
<div class="alert alert-info"><i class="ti ti-info-circle alert-ic"></i><span>Блок «Результат» обновляется вживую по текущим настройкам и выделению. Режим влияет, когда ширина и высота меняют пропорции оригинала: <b>Обрезать</b> — заполнить и срезать лишнее, <b>Вписать</b> — целиком с полями, <b>Уменьшить</b> — только уменьшить без обрезки, <b>Растянуть</b> — точно в размер.</span></div>
<div class="media-tool-group">
<button class="btn btn-secondary" type="button" data-crop-reset><i class="ti ti-crop"></i>Сбросить crop</button>
{% if file.extension != 'webp' and not file.has_webp and supports_webp %}
<button class="btn btn-secondary" type="button" data-media-webp data-path="{{ file.path }}"><i class="ti ti-file-type-jpg"></i>В WebP</button>
{% elseif file.extension != 'webp' and not file.has_webp %}
<button class="btn btn-secondary" type="button" disabled data-tooltip="PHP GD собран без WebP"><i class="ti ti-file-type-jpg"></i>В WebP</button>
{% endif %}
<button class="btn btn-secondary" type="button" data-media-result-zoom data-tooltip="Открыть результат крупно"><i class="ti ti-arrows-maximize"></i>Крупно</button>
<button class="btn btn-primary" type="submit"><i class="ti ti-wand"></i>Создать копию</button>
</div>
{% if file.extension != 'webp' and file.has_webp %}
<div class="alert alert-success"><i class="ti ti-file-check alert-ic"></i><span>WebP-копия уже есть: <a href="{{ ADMINX_BASE }}/media/file?path={{ file.webp_path|url_encode }}">{{ file.webp_path }}</a></span></div>
{% elseif file.extension != 'webp' and not supports_webp %}
<div class="alert alert-warning"><i class="ti ti-alert-triangle alert-ic"></i><span>WebP-конвертация требует PHP GD с поддержкой WebP: функций <code>imagewebp</code> и <code>imagecreatefromwebp</code>.</span></div>
{% else %}
<div class="alert alert-integration"><i class="ti ti-folder-cog alert-ic"></i><span>Копия будет сохранена в подпапку <code>_derivatives</code>, WebP-конвертация создаёт соседний файл <code>{{ file.webp_path }}</code>.</span></div>
{% endif %}
</form>
{% endif %}
{% else %}
<div class="alert alert-neutral"><i class="ti ti-lock alert-ic"></i><span>Для изменения файлов нужны права управления медиа.</span></div>
{% endif %}
</aside>
</div>
{% if can_manage %}
<form id="mediaActionForm" method="post">
<input type="hidden" name="_csrf" value="{{ csrf_token }}">
<input type="hidden" name="path" value="">
<input type="hidden" name="name" value="">
</form>
<div class="media-lightbox" data-media-lightbox hidden>
<div class="media-lightbox-panel" role="dialog" aria-modal="true" aria-label="Предпросмотр результата">
<div class="media-lightbox-head">
<div>
<h2 data-media-lightbox-title>Предпросмотр</h2>
<p class="text-secondary" data-media-lightbox-meta></p>
</div>
<button class="btn btn-ghost btn-icon" type="button" data-media-lightbox-close aria-label="Закрыть"><i class="ti ti-x"></i></button>
</div>
<div class="media-lightbox-stage">
<img src="" alt="" data-media-lightbox-image>
</div>
</div>
</div>
{% endif %}
{% endblock %}