Add secret management guide, client-side performance monitoring, and search accessibility enhancements

- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols.
- Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage.
- Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
This commit is contained in:
pacnpal
2025-12-23 16:41:42 -05:00
parent ae31e889d7
commit edcd8f2076
155 changed files with 22046 additions and 4645 deletions

View File

@@ -26,63 +26,52 @@
{% if is_edit %}Edit{% else %}Create{% endif %} Park
</h1>
<form method="post" enctype="multipart/form-data" class="space-y-6" x-data="parkForm()">
<form method="post" enctype="multipart/form-data" class="space-y-6" role="form" aria-label="{% if is_edit %}Edit park{% else %}Create new park{% endif %}" x-data="parkForm()">
{% csrf_token %}
{# Basic Information #}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Basic Information</h2>
<fieldset class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<legend class="mb-4 text-xl font-semibold">Basic Information</legend>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="col-span-2">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Name
</label>
{{ form.name }}
{% include 'forms/partials/form_field.html' with field=form.name label="Name" %}
</div>
<div class="col-span-2">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Description
</label>
{{ form.description }}
{% include 'forms/partials/form_field.html' with field=form.description label="Description" %}
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Owner/Operator
</label>
{{ form.owner }}
{% include 'forms/partials/form_field.html' with field=form.owner label="Owner/Operator" %}
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Status
</label>
{{ form.status }}
{% include 'forms/partials/form_field.html' with field=form.status label="Status" %}
</div>
</div>
</div>
</fieldset>
{# Location #}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Location</h2>
<fieldset class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<legend class="mb-4 text-xl font-semibold">Location</legend>
{% include "parks/partials/location_widget.html" %}
</div>
</fieldset>
{# Photos #}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Photos</h2>
<fieldset class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<legend class="mb-4 text-xl font-semibold">Photos</legend>
{# Existing Photos #}
{% if park.photos.exists %}
<div class="grid grid-cols-1 gap-4 mb-4 md:grid-cols-2 lg:grid-cols-3">
{% for photo in park.photos.all %}
<div class="relative overflow-hidden rounded-lg aspect-w-16 aspect-h-9">
<img src="{{ photo.image.url }}"
<img src="{{ photo.image.url }}"
alt="{{ photo.caption|default:park.name }}"
class="object-cover w-full h-full">
<div class="absolute top-0 right-0 p-2">
<button type="button"
<button type="button"
class="p-2 text-white bg-red-600 rounded-full hover:bg-red-700"
@click="removePhoto('{{ photo.id }}')">
<i class="fas fa-times"></i>
@click="removePhoto('{{ photo.id }}')"
aria-label="Remove photo">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
</div>
</div>
@@ -92,121 +81,114 @@
{# Photo Upload #}
<div class="space-y-4">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300" id="photo-upload-label">
Add Photos
</label>
<div class="relative">
<input type="file"
multiple
<input type="file"
multiple
accept="image/*"
class="hidden"
x-ref="fileInput"
@change="handleFileSelect">
@change="handleFileSelect"
aria-labelledby="photo-upload-label">
<button type="button"
class="w-full px-4 py-2 text-gray-700 border-2 border-dashed rounded-lg dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700"
@click="$refs.fileInput.click()">
<span x-show="!previews.length">
<i class="mr-2 fas fa-upload"></i>
<i class="mr-2 fas fa-upload" aria-hidden="true"></i>
Click to upload photos
</span>
<span x-show="previews.length">
<i class="mr-2 fas fa-plus"></i>
<i class="mr-2 fas fa-plus" aria-hidden="true"></i>
Add more photos
</span>
</button>
</div>
{# Photo Previews #}
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3" role="list" aria-label="Photo previews">
<template x-for="(preview, index) in previews" :key="preview.id">
<div class="relative overflow-hidden transition-all duration-300 rounded-lg aspect-w-16 aspect-h-9 photo-preview"
role="listitem"
:class="{
'uploading': preview.uploading,
'error': preview.error,
'success': preview.uploaded
}">
<img :src="preview.url"
class="object-cover w-full h-full">
<img :src="preview.url"
class="object-cover w-full h-full"
alt="Preview image">
<div class="absolute top-0 right-0 p-2">
<button type="button"
<button type="button"
class="p-2 text-white bg-red-600 rounded-full hover:bg-red-700"
@click="removePreview(index)">
<i class="fas fa-times"></i>
@click="removePreview(index)"
aria-label="Remove preview">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
</div>
<div x-show="preview.uploading"
<div x-show="preview.uploading"
class="absolute inset-0 flex items-center justify-center bg-black/50">
<div class="w-16 h-16 border-4 border-blue-500 rounded-full animate-spin border-t-transparent"></div>
<div class="w-16 h-16 border-4 border-blue-500 rounded-full animate-spin border-t-transparent" role="status" aria-label="Uploading"></div>
</div>
<div x-show="preview.error"
class="absolute bottom-0 left-0 right-0 p-2 text-sm text-white bg-red-500">
<div x-show="preview.error"
class="absolute bottom-0 left-0 right-0 p-2 text-sm text-white bg-red-500" role="alert">
Upload failed
</div>
</div>
</template>
</div>
</div>
</div>
</fieldset>
{# Additional Details #}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Additional Details</h2>
<fieldset class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<legend class="mb-4 text-xl font-semibold">Additional Details</legend>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Opening Date
</label>
{{ form.opening_date }}
{% include 'forms/partials/form_field.html' with field=form.opening_date label="Opening Date" %}
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Closing Date
</label>
{{ form.closing_date }}
{% include 'forms/partials/form_field.html' with field=form.closing_date label="Closing Date" %}
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Operating Season
</label>
{{ form.operating_season }}
{% include 'forms/partials/form_field.html' with field=form.operating_season label="Operating Season" %}
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Size (acres)
</label>
{{ form.size_acres }}
{% include 'forms/partials/form_field.html' with field=form.size_acres label="Size (acres)" %}
</div>
<div class="col-span-2">
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Website
</label>
{{ form.website }}
{% include 'forms/partials/form_field.html' with field=form.website label="Website" %}
</div>
</div>
</div>
</fieldset>
{# Submission Details #}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Submission Details</h2>
<fieldset class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<legend class="mb-4 text-xl font-semibold">Submission Details</legend>
<div class="space-y-4">
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="id_reason" class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Reason for Changes
</label>
<textarea name="reason" rows="2"
<textarea name="reason" id="id_reason" rows="2"
class="w-full px-4 py-2 border border-gray-300 rounded-lg form-textarea dark:border-gray-600 dark:bg-gray-700 dark:text-white"
placeholder="Explain why you're making these changes"></textarea>
placeholder="Explain why you're making these changes"
aria-describedby="reason-help"></textarea>
<p id="reason-help" class="mt-1 text-xs text-gray-500 dark:text-gray-400">Optional: Provide context for reviewers</p>
</div>
<div>
<label class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
<label for="id_source" class="block mb-1 text-sm font-medium text-gray-700 dark:text-gray-300">
Source
</label>
<input type="text" name="source"
<input type="text" name="source" id="id_source"
class="w-full px-4 py-2 border border-gray-300 rounded-lg form-input dark:border-gray-600 dark:bg-gray-700 dark:text-white"
placeholder="Where did you get this information?">
placeholder="Where did you get this information?"
aria-describedby="source-help">
<p id="source-help" class="mt-1 text-xs text-gray-500 dark:text-gray-400">Optional: Link or reference to your source</p>
</div>
</div>
</div>
</fieldset>
{# Submit Button #}
<div class="flex justify-end">