Enhance website security and add SEO meta tags for better visibility

Implement robust security headers, including CSP with nonces, and integrate comprehensive SEO meta tags into the base template and homepage. Add inline styles for CSP compliance and improve theme management script for immediate theme application.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 48ecdb60-d0f0-4b75-95c9-34e409ef35fb
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
This commit is contained in:
pac7
2025-09-22 16:06:47 +00:00
parent 95f94cc799
commit 6697d8890b
9 changed files with 315 additions and 52 deletions

View File

@@ -5,30 +5,68 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="csrf-token" content="{{ csrf_token }}" />
<!-- SEO Meta Tags -->
<title>{% block title %}ThrillWiki{% endblock %}</title>
<meta name="description" content="{% block meta_description %}Your ultimate guide to theme parks and attractions worldwide. Discover thrilling rides, explore amazing parks, and share your adventures with fellow enthusiasts.{% endblock %}" />
<meta name="keywords" content="{% block meta_keywords %}theme parks, roller coasters, attractions, rides, amusement parks, Disney, Universal, Cedar Point{% endblock %}" />
<meta name="author" content="ThrillWiki" />
<meta name="robots" content="{% block meta_robots %}index, follow{% endblock %}" />
<link rel="canonical" href="{% block canonical_url %}{{ request.scheme }}://{{ request.get_host }}{{ request.path }}{% endblock %}" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="{% block og_type %}website{% endblock %}" />
<meta property="og:url" content="{% block og_url %}{{ request.build_absolute_uri|default:'' }}{% endblock %}" />
<meta property="og:title" content="{% block og_title %}ThrillWiki{% endblock %}" />
<meta property="og:description" content="{% block og_description %}Your ultimate guide to theme parks and attractions worldwide. Discover thrilling rides, explore amazing parks, and share your adventures with fellow enthusiasts.{% endblock %}" />
<meta property="og:image" content="{% block og_image %}{% load static %}{{ request.scheme }}://{{ request.get_host }}{% static 'images/placeholders/default-park.jpg' %}{% endblock %}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:site_name" content="ThrillWiki" />
<meta property="og:locale" content="en_US" />
<!-- Twitter -->
<meta name="twitter:card" content="{% block twitter_card %}summary_large_image{% endblock %}" />
<meta name="twitter:url" content="{% block twitter_url %}{{ request.build_absolute_uri|default:'' }}{% endblock %}" />
<meta name="twitter:title" content="{% block twitter_title %}ThrillWiki{% endblock %}" />
<meta name="twitter:description" content="{% block twitter_description %}Your ultimate guide to theme parks and attractions worldwide. Discover thrilling rides, explore amazing parks, and share your adventures with fellow enthusiasts.{% endblock %}" />
<meta name="twitter:image" content="{% block twitter_image %}{% load static %}{{ request.scheme }}://{{ request.get_host }}{% static 'images/placeholders/default-park.jpg' %}{% endblock %}" />
<meta name="twitter:creator" content="@ThrillWiki" />
<meta name="twitter:site" content="@ThrillWiki" />
<!-- Google Fonts -->
<!-- Resource Hints for Performance -->
<link rel="dns-prefetch" href="//fonts.googleapis.com" />
<link rel="dns-prefetch" href="//fonts.gstatic.com" />
<link rel="dns-prefetch" href="//unpkg.com" />
<link rel="dns-prefetch" href="//cdnjs.cloudflare.com" />
{% block extra_dns_prefetch %}{% endblock %}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
{% block extra_preconnect %}{% endblock %}
<!-- Preload Critical Resources -->
{% block critical_resources %}
<link rel="preload" href="{% static 'css/tailwind.css' %}" as="style" />
<link rel="preload" href="{% static 'js/theme.js' %}?v={{ version|default:'1.0' }}" as="script" />
<link rel="preload" href="{% static 'js/alpine.min.js' %}?v={{ version|default:'1.0' }}" as="script" />
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" as="style" />
{% endblock %}
<!-- Module Preload for Modern Browsers -->
{% block module_preload %}{% endblock %}
<!-- Google Fonts with performance optimizations -->
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<!-- Prevent flash of wrong theme -->
<script>
let theme = localStorage.getItem("theme");
if (!theme) {
theme = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
localStorage.setItem("theme", theme);
}
if (theme === "dark") {
document.documentElement.classList.add("dark");
}
</script>
<script src="{% static 'js/theme.js' %}?v={{ version|default:'1.0' }}"></script>
<!-- HTMX -->
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
<script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FYYOtJ1BoGZ1EZbdLzmaydhwRKh5zxCwWA0jzNEzSJYTzFxN2wjCjOj3gLyQYZGC" crossorigin="anonymous"></script>
<!-- Alpine.js Components (must load before Alpine.js) -->
<script src="{% static 'js/alpine-components.js' %}?v={{ version|default:'1.0' }}"></script>
@@ -43,75 +81,85 @@
<link href="{% static 'css/tailwind.css' %}" rel="stylesheet" />
<link href="{% static 'css/components.css' %}" rel="stylesheet" />
<link href="{% static 'css/alerts.css' %}" rel="stylesheet" />
<link href="{% static 'css/inline-styles.css' %}" rel="stylesheet" />
<!-- Font Awesome -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
integrity="sha512-9usAa10IRO0HhonpyAIVpjrylPvoDwiPUiKdWk5t3PyolY1cOd4DSE0Ga+ri4AuTroPR5aQvXU9xC6qOPnzFeg=="
crossorigin="anonymous"
/>
<style>
[x-cloak] {
display: none !important;
}
.dropdown-menu {
position: absolute;
right: 0;
margin-top: 0.5rem;
width: 12rem;
border-radius: 0.375rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
z-index: 50;
overflow: hidden;
}
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: block;
}
.htmx-request.htmx-indicator {
display: block;
}
</style>
<!-- Structured Data (JSON-LD) -->
{% block structured_data %}
<script type="application/ld+json" nonce="{{ request.csp_nonce }}">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "ThrillWiki",
"description": "Your ultimate guide to theme parks and attractions worldwide",
"url": "{{ request.scheme }}://{{ request.get_host }}",
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "{{ request.scheme }}://{{ request.get_host }}/search/?q={search_term_string}"
},
"query-input": "required name=search_term_string"
},
"author": {
"@type": "Organization",
"name": "ThrillWiki"
}
}
</script>
{% endblock %}
{% block extra_head %}{% endblock %}
</head>
<body
class="flex flex-col min-h-screen text-gray-900 bg-gradient-to-br from-white via-blue-50 to-indigo-50 dark:from-gray-950 dark:via-indigo-950 dark:to-purple-950 dark:text-white"
{% block body_attributes %}{% endblock %}
>
<!-- Skip to content link for accessibility -->
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">Skip to main content</a>
<!-- Enhanced Header -->
{% include 'components/layout/enhanced_header.html' %}
<!-- Flash Messages -->
{% if messages %}
<div class="fixed top-0 right-0 z-50 p-4 space-y-4">
<div class="fixed top-0 right-0 z-50 p-4 space-y-4" role="alert" aria-live="polite" aria-label="Notifications">
{% for message in messages %}
<div
class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}"
role="alert"
aria-describedby="alert-{{ forloop.counter }}"
>
{{ message }}
<span id="alert-{{ forloop.counter }}">{{ message }}</span>
</div>
{% endfor %}
</div>
{% endif %}
<!-- Main Content -->
<main class="container flex-grow px-6 py-8 mx-auto">
<main id="main-content" class="container flex-grow px-6 py-8 mx-auto" role="main">
{% block content %}{% endblock %}
</main>
<!-- Footer -->
<footer
class="mt-auto border-t bg-white/90 dark:bg-gray-800/90 backdrop-blur-lg border-gray-200/50 dark:border-gray-700/50"
role="contentinfo"
aria-label="Site footer"
>
<div class="container px-6 py-6 mx-auto">
<div class="flex items-center justify-between">
<div class="text-gray-600 dark:text-gray-400">
<p>&copy; {% now "Y" %} ThrillWiki. All rights reserved.</p>
</div>
<div class="space-x-4">
<nav class="space-x-4" role="navigation" aria-label="Footer links">
<a
href="{% url 'terms' %}"
class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary"
@@ -122,7 +170,7 @@
class="text-gray-600 transition-colors hover:text-primary dark:text-gray-400 dark:hover:text-primary"
>Privacy</a
>
</div>
</nav>
</div>
</div>
</footer>
@@ -137,10 +185,6 @@
<script src="{% static 'js/main.js' %}?v={{ version|default:'1.0' }}"></script>
<script src="{% static 'js/alerts.js' %}?v={{ version|default:'1.0' }}"></script>
<!-- Cache control meta tag -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
{% block extra_js %}{% endblock %}
</body>
</html>