- PluginManager: getAdminMenuItems(), handleAdminRoute(), getPluginType() - admin.php: load PluginManager, pass plugin_admin_menu to Twig - admin.php: route to plugin admin pages via handleAdminRoute() - admin.twig: show 'Plugins' sidebar section for system plugins - plugins-new.twig: choose content or system plugin type - handlePluginsNew: generate proper template based on type (content/system) - plugin-admin.twig: renders plugin output in admin layout - GeoIPInfo: example system plugin (admin page with GeoIP info) - System plugins: getAdminMenu(), getAdminRoutes(), handleAdminRoute() - Content plugins: getSidebarContent() (unchanged)
150 lines
4.4 KiB
Twig
150 lines
4.4 KiB
Twig
<!DOCTYPE html>
|
|
<html lang="{{ current_lang }}">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{ page_title }} - {{ site_title }}</title>
|
|
|
|
<!-- Skip to content link for accessibility -->
|
|
<a href="#main-content" class="skip-link sr-only sr-only-focusable">Skip to main content</a>
|
|
|
|
<!-- CMS Meta Tags -->
|
|
<meta name="generator" content="{{ site_title }} CMS">
|
|
<meta name="application-name" content="{{ site_title }}">
|
|
<meta name="author" content="{{ author_name }}">
|
|
<meta name="creator" content="{{ author_name }}">
|
|
<meta name="publisher" content="{{ author_name }}">
|
|
|
|
<!-- SEO Meta Tags -->
|
|
<meta name="description" content="{{ seo_description }}">
|
|
<meta name="keywords" content="{{ seo_keywords }}">
|
|
{% if block_ai_bots %}
|
|
<meta name="robots" content="noai, noimageai">
|
|
<meta name="tdm-reservation" content="1">
|
|
{% endif %}
|
|
{% if block_search_engines %}
|
|
<meta name="robots" content="noindex, nofollow">
|
|
{% endif %}
|
|
|
|
<!-- Author Links -->
|
|
<link rel="author" href="{{ author_website }}">
|
|
<link rel="me" href="{{ author_git }}">
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" type="image/x-icon" href="{{ theme_base_url }}/assets/img/favicon.ico">
|
|
<link rel="icon" type="image/svg+xml" href="{{ theme_base_url }}/assets/img/favicon.svg">
|
|
<link rel="apple-touch-icon" href="{{ theme_base_url }}/assets/img/favicon.svg">
|
|
<link rel="manifest" href="/manifest.json">
|
|
<meta name="theme-color" content="{{ theme_config.header_color|default('#0a369d') }}">
|
|
|
|
<!-- Theme CSS -->
|
|
{% for cssFile in theme_css_files %}
|
|
<link href="{{ cssFile }}" rel="stylesheet">
|
|
{% endfor %}
|
|
|
|
<!-- Compiled theme CSS (if SCSS was used) -->
|
|
{% if theme_css_url %}
|
|
<link href="{{ theme_css_url }}" rel="stylesheet">
|
|
{% endif %}
|
|
|
|
<!-- Plugin CSS (loaded after theme so theme can override) -->
|
|
{% for cssUrl in plugin_css_urls|default([]) %}
|
|
<link href="{{ cssUrl }}" rel="stylesheet">
|
|
{% endfor %}
|
|
|
|
<!-- Accessibility styles -->
|
|
<style>
|
|
.skip-link {
|
|
position: absolute;
|
|
top: -40px;
|
|
left: 6px;
|
|
background: #000;
|
|
color: #fff;
|
|
padding: 8px;
|
|
text-decoration: none;
|
|
z-index: 100;
|
|
}
|
|
.skip-link:focus {
|
|
top: 6px;
|
|
outline: 3px solid #0056b3;
|
|
outline-offset: 2px;
|
|
}
|
|
.sr-only {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
.sr-only-focusable:focus {
|
|
position: static;
|
|
width: auto;
|
|
height: auto;
|
|
padding: inherit;
|
|
margin: inherit;
|
|
overflow: visible;
|
|
clip: auto;
|
|
white-space: normal;
|
|
}
|
|
</style>
|
|
|
|
<!-- Dynamic theme styles -->
|
|
<style>
|
|
html {
|
|
min-height: 100%;
|
|
}
|
|
|
|
body {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
#site-header > * {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
{% include 'partials/header.twig' %}
|
|
|
|
<nav role="navigation" aria-label="Main navigation" id="site-navigation">
|
|
{% include 'partials/navigation.twig' %}
|
|
</nav>
|
|
|
|
<nav id="site-breadcrumb" class="breadcrumb-section bg-light border-bottom" aria-label="Breadcrumb navigation">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12 py-2">
|
|
<h2 class="sr-only">Breadcrumb Navigation</h2>
|
|
{{ breadcrumb|raw }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main role="main" id="main-content" class="main-content" style="padding: 0;">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<footer role="contentinfo" id="site-footer">
|
|
{% include 'partials/footer.twig' %}
|
|
</footer>
|
|
|
|
<!-- Theme JS -->
|
|
{% for jsFile in theme_js_files %}
|
|
<script src="{{ jsFile }}"></script>
|
|
{% endfor %}
|
|
|
|
<!-- Theme-specific JS -->
|
|
{% if theme_js_url %}
|
|
<script src="{{ theme_js_url }}"></script>
|
|
{% endif %}
|
|
</body>
|
|
</html>
|