v2.6.3 (Lyra): Content multi-type handling, getAllPages() structuur, . verberg-prefix
- Content bestanden met dezelfde naam maar ander type (md/php/html) worden correct geserveerd: URL met extensie opent dat bestand, URL zonder extensie valt terug op md > php > html (resolveContentByType helper) - Admin content editor accepteert bestanden met dezelfde naam (ander type); preview-knop linkt per extensie - Frontend navigatie/directory listing/search tonen elk bestandstype apart - getAllPages() array structuur gewijzigd naar list van ['path','title','type'] met type 'md'/'php'/'html'/'folder' - Verberg-prefix logica: _ is geen verberg-prefix meer, alleen . (en -); admin toont wél alle . bestanden/mappen - ContentAPI getPage()/pageExists() respecteren expliciete extensie - Handleiding content-api.md (NL+EN) herschreven - File-tree unificatie: _file-tree.twig + _editor-styles.twig includes - Versie verhoogd naar 2.6.3
This commit is contained in:
@@ -2,98 +2,12 @@
|
||||
|
||||
{% block title %}{{ ta.theme_edit|default('Thema bewerken: ') }}{{ themeName }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
|
||||
|
||||
{# Recursively render the theme file tree as a nested, collapsible list.
|
||||
A folder is expanded by default when the currently selected file lives
|
||||
somewhere inside it, so the user always sees where their file is. #}
|
||||
{% macro tree(nodes, themeName, relFile, editableExts, csrfToken) %}
|
||||
{% import _self as macros %}
|
||||
<ul class="plugin-tree">
|
||||
{% for n in nodes %}
|
||||
{% set isActive = n.path == relFile %}
|
||||
{% set containsActive = n.is_dir and relFile starts with (n.path ~ '/') %}
|
||||
{% set icon = n.is_dir ? 'bi-folder-fill text-warning' : (n.extension == 'twig' ? 'bi-filetype-tfn text-info' : (n.extension == 'php' ? 'bi-file-code text-success' : (n.extension == 'json' ? 'bi-filetype-json text-secondary' : (n.extension == 'md' ? 'bi-file-text text-primary' : (n.extension in ['css','scss'] ? 'bi-filetype-css text-info' : (n.extension == 'js' ? 'bi-filetype-js text-warning' : (n.extension == 'html' ? 'bi-file-earmark text-info' : 'bi-file text-muted'))))))) %}
|
||||
<li>
|
||||
{% if n.is_dir %}
|
||||
{% set collapseId = 'theme-tree-' ~ n.path|replace({'/':'-','.':'-'}) %}
|
||||
<button type="button" class="tree-link tree-toggle btn-toggle {{ containsActive ? '' : 'collapsed' }}"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#{{ collapseId }}"
|
||||
aria-expanded="{{ containsActive ? 'true' : 'false' }}"
|
||||
title="{{ n.path }}">
|
||||
<i class="bi bi-chevron-down tree-chevron"></i>
|
||||
<i class="bi {{ icon }}"></i>
|
||||
<span class="text-truncate">{{ n.name }}</span>
|
||||
</button>
|
||||
<div id="{{ collapseId }}"
|
||||
class="tree-collapse collapse {{ containsActive ? 'show' : '' }}">
|
||||
{% if n.children is not empty %}
|
||||
{{ macros.tree(n.children, themeName, relFile, editableExts, csrfToken) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="/admin/theme-edit?theme={{ themeName|url_encode }}&file={{ n.path|url_encode }}"
|
||||
class="tree-link {{ isActive ? 'is-active' : '' }}"
|
||||
title="{{ n.path }}">
|
||||
<span class="tree-chevron-spacer"></span>
|
||||
<i class="bi {{ icon }}"></i>
|
||||
<span class="text-truncate">{{ n.name }}</span>
|
||||
{% if n.extension in editableExts %}
|
||||
<span class="badge bg-secondary badge-ext">{{ n.extension|upper }}</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% if n.path != 'theme.json' %}
|
||||
<a href="/admin/theme-file-move?theme={{ themeName|url_encode }}&file={{ n.path|url_encode }}"
|
||||
class="tree-move-btn" title="{{ ta.move|default('Verplaatsen') }}" aria-label="{{ ta.move|default('Verplaatsen') }}">
|
||||
<i class="bi bi-arrows-move"></i>
|
||||
</a>
|
||||
<form method="POST" action="/admin/theme-file-delete" class="tree-delete-form" onsubmit="return confirm('{{ ta.confirm_delete_file|default('Weet je zeker dat je dit bestand wilt verwijderen?') }}')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrfToken }}">
|
||||
<input type="hidden" name="theme" value="{{ themeName }}">
|
||||
<input type="hidden" name="file" value="{{ n.path }}">
|
||||
<button type="submit" class="btn btn-link btn-sm text-danger p-0 ms-1 tree-delete-btn" title="{{ ta.delete|default('Verwijderen') }}" aria-label="{{ ta.delete|default('Verwijderen') }}">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
{% import _self as tree_macros %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="/admin/assets/codemirror/codemirror.min.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/editor.css">
|
||||
{% include 'pages/_editor-styles.twig' %}
|
||||
<style>
|
||||
.plugin-editor-layout { display: flex; gap: 1rem; align-items: stretch; }
|
||||
.plugin-file-tree { width: 280px; flex: 0 0 280px; }
|
||||
.plugin-editor-main { flex: 1 1 auto; min-width: 0; }
|
||||
.plugin-tree { list-style: none; padding-left: 0; margin: 0; }
|
||||
.plugin-tree ul { list-style: none; padding-left: 1.1rem; margin: 0; }
|
||||
.plugin-tree li { padding: 0; position: relative; }
|
||||
.plugin-tree li > .tree-link { display: flex; align-items: center; gap: .3rem; padding: .2rem .4rem; border-radius: .25rem; text-decoration: none; color: inherit; font-size: .9rem; line-height: 1.4; }
|
||||
.plugin-tree li > .tree-link:hover { background-color: rgba(13,110,253,.08); }
|
||||
.plugin-tree li > .tree-link.is-active { background-color: var(--bs-primary-bg-subtle, #cfe2ff); font-weight: 600; }
|
||||
.plugin-tree .tree-toggle { cursor: pointer; user-select: none; width: 100%; text-align: left; background: transparent; border: 0; color: inherit; }
|
||||
.plugin-tree .tree-chevron { transition: transform .15s ease; flex: 0 0 auto; }
|
||||
.plugin-tree .tree-chevron-spacer { display: inline-block; width: .9rem; flex: 0 0 auto; }
|
||||
.plugin-tree .btn-toggle.collapsed .tree-chevron { transform: rotate(-90deg); }
|
||||
.plugin-tree .badge-ext { font-size: .6rem; margin-left: auto; }
|
||||
.plugin-tree .text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.plugin-tree .tree-delete-form { position: absolute; right: .25rem; top: 50%; transform: translateY(-50%); margin: 0; }
|
||||
.plugin-tree .tree-delete-btn { font-size: .9rem; line-height: 1; padding: .15rem; color: #dc3545; background: transparent; border: 0; }
|
||||
.plugin-tree .tree-delete-btn:hover { color: #b02a37; }
|
||||
.plugin-tree .tree-move-btn { position: absolute; right: 1.75rem; top: 50%; transform: translateY(-50%); font-size: .9rem; line-height: 1; padding: .15rem; color: #6c757d; text-decoration: none; }
|
||||
.plugin-tree .tree-move-btn:hover { color: #0d6efd; }
|
||||
.plugin-tree li > .tree-link { padding-right: 3.5rem; }
|
||||
.plugin-file-tree .card-body { max-height: 70vh; overflow-y: auto; }
|
||||
.theme-scss-status { font-size: .75rem; }
|
||||
@media (max-width: 768px) {
|
||||
.plugin-editor-layout { flex-direction: column; }
|
||||
.plugin-file-tree { width: 100%; flex-basis: auto; max-height: 320px; }
|
||||
.plugin-file-tree .card-body { max-height: 260px; }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -144,25 +58,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="plugin-editor-layout">
|
||||
{# File tree sidebar #}
|
||||
<div class="plugin-file-tree">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-header bg-white py-2 d-flex justify-content-between align-items-center">
|
||||
<span class="small text-muted fw-semibold"><i class="bi bi-folder2-open"></i> {{ ta.theme_files|default('Thema bestanden') }}</span>
|
||||
</div>
|
||||
<div class="card-body p-2" id="pluginFileTree">
|
||||
{% if files is empty %}
|
||||
<div class="small text-muted p-2">{{ ta.theme_no_files|default('Geen bestanden gevonden.') }}</div>
|
||||
{% else %}
|
||||
{{ tree_macros.tree(files, themeName, relFile, editableExts, csrf_token) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-layout">
|
||||
{# File tree sidebar (shared partial) #}
|
||||
{% include 'pages/_file-tree.twig' with {
|
||||
'files': files,
|
||||
'relFile': relFile,
|
||||
'editableExts': editableExts,
|
||||
'csrf_token': csrf_token,
|
||||
'treeIdPrefix': 'theme-tree',
|
||||
'treeHeader': ta.theme_files|default('Thema bestanden'),
|
||||
'treeEmptyText': ta.theme_no_files|default('Geen bestanden gevonden.'),
|
||||
'treeRouteBase': '/admin/theme-edit',
|
||||
'treeRouteParams': 'theme=' ~ themeName|url_encode ~ '&',
|
||||
'treeDeleteRoute': '/admin/theme-file-delete',
|
||||
'treeDeleteName': 'theme',
|
||||
'treeDeleteValue': themeName,
|
||||
'treeMoveRoute': '/admin/theme-file-move',
|
||||
'treeMoveParams': 'theme=' ~ themeName|url_encode ~ '&',
|
||||
'treeDirActions': false,
|
||||
'treeHideActionsFor': ['theme.json'],
|
||||
} %}
|
||||
|
||||
{# Editor main panel #}
|
||||
<div class="plugin-editor-main">
|
||||
<div class="editor-main">
|
||||
{% if relFile %}
|
||||
<nav aria-label="breadcrumb" class="mb-2">
|
||||
<ol class="breadcrumb mb-0">
|
||||
|
||||
Reference in New Issue
Block a user