mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:31:07 -05:00
Standardize park and ride cards with django-cotton component
Updates CSS with new Tailwind classes and refactors ride card template to use django-cotton, implementing park-specific URL generation and graceful handling of missing slugs. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 0bdea3fb-49ea-4863-b501-fa6f5af0cbf0 Replit-Commit-Checkpoint-Type: intermediate_checkpoint
This commit is contained in:
2
.replit
2
.replit
@@ -55,7 +55,7 @@ localPort = 5000
|
|||||||
externalPort = 80
|
externalPort = 80
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
localPort = 35685
|
localPort = 37689
|
||||||
externalPort = 3002
|
externalPort = 3002
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
|
|||||||
@@ -410,6 +410,9 @@
|
|||||||
.top-0 {
|
.top-0 {
|
||||||
top: calc(var(--spacing) * 0);
|
top: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.top-1 {
|
||||||
|
top: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.top-1\/2 {
|
.top-1\/2 {
|
||||||
top: calc(1/2 * 100%);
|
top: calc(1/2 * 100%);
|
||||||
}
|
}
|
||||||
@@ -449,6 +452,9 @@
|
|||||||
.left-0 {
|
.left-0 {
|
||||||
left: calc(var(--spacing) * 0);
|
left: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.left-1 {
|
||||||
|
left: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.left-1\/2 {
|
.left-1\/2 {
|
||||||
left: calc(1/2 * 100%);
|
left: calc(1/2 * 100%);
|
||||||
}
|
}
|
||||||
@@ -527,6 +533,9 @@
|
|||||||
max-width: 96rem;
|
max-width: 96rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.-mx-1 {
|
||||||
|
margin-inline: calc(var(--spacing) * -1);
|
||||||
|
}
|
||||||
.-mx-1\.5 {
|
.-mx-1\.5 {
|
||||||
margin-inline: calc(var(--spacing) * -1.5);
|
margin-inline: calc(var(--spacing) * -1.5);
|
||||||
}
|
}
|
||||||
@@ -545,6 +554,9 @@
|
|||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
|
.-my-1 {
|
||||||
|
margin-block: calc(var(--spacing) * -1);
|
||||||
|
}
|
||||||
.-my-1\.5 {
|
.-my-1\.5 {
|
||||||
margin-block: calc(var(--spacing) * -1.5);
|
margin-block: calc(var(--spacing) * -1.5);
|
||||||
}
|
}
|
||||||
@@ -554,6 +566,9 @@
|
|||||||
.my-auto {
|
.my-auto {
|
||||||
margin-block: auto;
|
margin-block: auto;
|
||||||
}
|
}
|
||||||
|
.mt-0 {
|
||||||
|
margin-top: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.mt-0\.5 {
|
.mt-0\.5 {
|
||||||
margin-top: calc(var(--spacing) * 0.5);
|
margin-top: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -626,6 +641,9 @@
|
|||||||
.mb-12 {
|
.mb-12 {
|
||||||
margin-bottom: calc(var(--spacing) * 12);
|
margin-bottom: calc(var(--spacing) * 12);
|
||||||
}
|
}
|
||||||
|
.-ml-0 {
|
||||||
|
margin-left: calc(var(--spacing) * -0);
|
||||||
|
}
|
||||||
.-ml-0\.5 {
|
.-ml-0\.5 {
|
||||||
margin-left: calc(var(--spacing) * -0.5);
|
margin-left: calc(var(--spacing) * -0.5);
|
||||||
}
|
}
|
||||||
@@ -797,6 +815,9 @@
|
|||||||
.min-h-screen {
|
.min-h-screen {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
.w-1 {
|
||||||
|
width: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.w-1\/2 {
|
.w-1\/2 {
|
||||||
width: calc(1/2 * 100%);
|
width: calc(1/2 * 100%);
|
||||||
}
|
}
|
||||||
@@ -932,6 +953,13 @@
|
|||||||
.grow {
|
.grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.-translate-x-1 {
|
||||||
|
--tw-translate-x: calc(var(--spacing) * -1);
|
||||||
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
|
}
|
||||||
.-translate-x-1\/2 {
|
.-translate-x-1\/2 {
|
||||||
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
@@ -948,6 +976,10 @@
|
|||||||
--tw-translate-x: 100%;
|
--tw-translate-x: 100%;
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
}
|
}
|
||||||
|
.-translate-y-1 {
|
||||||
|
--tw-translate-y: calc(var(--spacing) * -1);
|
||||||
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
|
}
|
||||||
.-translate-y-1\/2 {
|
.-translate-y-1\/2 {
|
||||||
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
||||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||||
@@ -1130,6 +1162,13 @@
|
|||||||
margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
|
margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.space-y-8 {
|
||||||
|
:where(& > :not(:last-child)) {
|
||||||
|
--tw-space-y-reverse: 0;
|
||||||
|
margin-block-start: calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));
|
||||||
|
margin-block-end: calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)));
|
||||||
|
}
|
||||||
|
}
|
||||||
.-space-x-px {
|
.-space-x-px {
|
||||||
:where(& > :not(:last-child)) {
|
:where(& > :not(:last-child)) {
|
||||||
--tw-space-x-reverse: 0;
|
--tw-space-x-reverse: 0;
|
||||||
@@ -1394,6 +1433,9 @@
|
|||||||
.bg-\[\#5865F2\] {
|
.bg-\[\#5865F2\] {
|
||||||
background-color: #5865F2;
|
background-color: #5865F2;
|
||||||
}
|
}
|
||||||
|
.bg-accent {
|
||||||
|
background-color: var(--color-accent);
|
||||||
|
}
|
||||||
.bg-accent\/10 {
|
.bg-accent\/10 {
|
||||||
background-color: color-mix(in srgb, #8b5cf6 10%, transparent);
|
background-color: color-mix(in srgb, #8b5cf6 10%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1442,6 +1484,9 @@
|
|||||||
.bg-blue-600 {
|
.bg-blue-600 {
|
||||||
background-color: var(--color-blue-600);
|
background-color: var(--color-blue-600);
|
||||||
}
|
}
|
||||||
|
.bg-blue-900 {
|
||||||
|
background-color: var(--color-blue-900);
|
||||||
|
}
|
||||||
.bg-blue-900\/40 {
|
.bg-blue-900\/40 {
|
||||||
background-color: color-mix(in srgb, oklch(37.9% 0.146 265.522) 40%, transparent);
|
background-color: color-mix(in srgb, oklch(37.9% 0.146 265.522) 40%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1496,6 +1541,9 @@
|
|||||||
.bg-green-600 {
|
.bg-green-600 {
|
||||||
background-color: var(--color-green-600);
|
background-color: var(--color-green-600);
|
||||||
}
|
}
|
||||||
|
.bg-green-900 {
|
||||||
|
background-color: var(--color-green-900);
|
||||||
|
}
|
||||||
.bg-green-900\/40 {
|
.bg-green-900\/40 {
|
||||||
background-color: color-mix(in srgb, oklch(39.3% 0.095 152.535) 40%, transparent);
|
background-color: color-mix(in srgb, oklch(39.3% 0.095 152.535) 40%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1550,6 +1598,9 @@
|
|||||||
.bg-red-600 {
|
.bg-red-600 {
|
||||||
background-color: var(--color-red-600);
|
background-color: var(--color-red-600);
|
||||||
}
|
}
|
||||||
|
.bg-red-900 {
|
||||||
|
background-color: var(--color-red-900);
|
||||||
|
}
|
||||||
.bg-red-900\/40 {
|
.bg-red-900\/40 {
|
||||||
background-color: color-mix(in srgb, oklch(39.6% 0.141 25.723) 40%, transparent);
|
background-color: color-mix(in srgb, oklch(39.6% 0.141 25.723) 40%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1607,6 +1658,9 @@
|
|||||||
.bg-yellow-600 {
|
.bg-yellow-600 {
|
||||||
background-color: var(--color-yellow-600);
|
background-color: var(--color-yellow-600);
|
||||||
}
|
}
|
||||||
|
.bg-yellow-900 {
|
||||||
|
background-color: var(--color-yellow-900);
|
||||||
|
}
|
||||||
.bg-yellow-900\/40 {
|
.bg-yellow-900\/40 {
|
||||||
background-color: color-mix(in srgb, oklch(42.1% 0.095 57.708) 40%, transparent);
|
background-color: color-mix(in srgb, oklch(42.1% 0.095 57.708) 40%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1625,6 +1679,10 @@
|
|||||||
--tw-gradient-position: to top in oklab;
|
--tw-gradient-position: to top in oklab;
|
||||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||||
}
|
}
|
||||||
|
.from-black {
|
||||||
|
--tw-gradient-from: var(--color-black);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
||||||
|
}
|
||||||
.from-black\/60 {
|
.from-black\/60 {
|
||||||
--tw-gradient-from: color-mix(in srgb, #000 60%, transparent);
|
--tw-gradient-from: color-mix(in srgb, #000 60%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1685,6 +1743,10 @@
|
|||||||
--tw-gradient-from: var(--color-red-500);
|
--tw-gradient-from: var(--color-red-500);
|
||||||
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
||||||
}
|
}
|
||||||
|
.from-secondary {
|
||||||
|
--tw-gradient-from: var(--color-secondary);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
||||||
|
}
|
||||||
.from-secondary\/20 {
|
.from-secondary\/20 {
|
||||||
--tw-gradient-from: color-mix(in srgb, #e11d48 20%, transparent);
|
--tw-gradient-from: color-mix(in srgb, #e11d48 20%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1720,6 +1782,10 @@
|
|||||||
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
|
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
|
||||||
--tw-gradient-stops: var(--tw-gradient-via-stops);
|
--tw-gradient-stops: var(--tw-gradient-via-stops);
|
||||||
}
|
}
|
||||||
|
.to-accent {
|
||||||
|
--tw-gradient-to: var(--color-accent);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
|
||||||
|
}
|
||||||
.to-accent\/20 {
|
.to-accent\/20 {
|
||||||
--tw-gradient-to: color-mix(in srgb, #8b5cf6 20%, transparent);
|
--tw-gradient-to: color-mix(in srgb, #8b5cf6 20%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1849,6 +1915,9 @@
|
|||||||
.px-8 {
|
.px-8 {
|
||||||
padding-inline: calc(var(--spacing) * 8);
|
padding-inline: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.py-0 {
|
||||||
|
padding-block: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.py-0\.5 {
|
.py-0\.5 {
|
||||||
padding-block: calc(var(--spacing) * 0.5);
|
padding-block: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -2185,6 +2254,9 @@
|
|||||||
.italic {
|
.italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
.underline-offset-4 {
|
.underline-offset-4 {
|
||||||
text-underline-offset: 4px;
|
text-underline-offset: 4px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,61 @@
|
|||||||
{% comment %}
|
{% comment %}
|
||||||
Ride Card Component - Django Cotton Version
|
Ride Card Component - Django Cotton Version
|
||||||
|
|
||||||
A comprehensive ride card component with image handling, status badges, and feature displays.
|
A comprehensive ride card component with image handling, status badges, feature displays,
|
||||||
Includes all ride statistics, special features, and manufacturer information.
|
and robust URL generation that supports both global and park-specific URL patterns.
|
||||||
|
Includes graceful handling of missing slugs to prevent 500 errors.
|
||||||
|
|
||||||
Usage Examples:
|
Usage Examples:
|
||||||
|
|
||||||
Basic usage:
|
Basic usage (default global URL pattern):
|
||||||
<c-ride_card ride=ride />
|
<c-ride_card ride=ride />
|
||||||
|
|
||||||
|
Park-specific URL pattern:
|
||||||
|
<c-ride_card ride=ride url_variant="park" />
|
||||||
|
|
||||||
With custom CSS classes:
|
With custom CSS classes:
|
||||||
<c-ride_card
|
<c-ride_card
|
||||||
ride=ride
|
ride=ride
|
||||||
|
url_variant="global"
|
||||||
class="custom-class"
|
class="custom-class"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
With custom image fallback:
|
With custom image fallback:
|
||||||
<c-ride_card
|
<c-ride_card
|
||||||
ride=ride
|
ride=ride
|
||||||
|
url_variant="park"
|
||||||
fallback_gradient="from-red-500 to-blue-600"
|
fallback_gradient="from-red-500 to-blue-600"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- ride: Ride object (required)
|
- ride: Ride object (required)
|
||||||
|
- url_variant: URL pattern type - 'global' (default) or 'park' (optional)
|
||||||
- class: Additional CSS classes (optional)
|
- class: Additional CSS classes (optional)
|
||||||
- fallback_gradient: Custom gradient for image fallback (default: "from-blue-500 to-purple-600")
|
- fallback_gradient: Custom gradient for image fallback (default: "from-blue-500 to-purple-600")
|
||||||
|
|
||||||
|
URL Pattern Logic:
|
||||||
|
- If url_variant='global' and ride.slug exists: uses rides:ride_detail with ride.slug
|
||||||
|
- If url_variant='park' and both ride.park.slug and ride.slug exist: uses parks:rides:ride_detail with ride.park.slug, ride.slug
|
||||||
|
- If no valid URL can be generated: renders ride name as plain text (no link)
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
- Graceful handling of missing slugs (prevents NoReverseMatch errors)
|
||||||
|
- Support for both global and park-specific URL patterns
|
||||||
- Image handling with gradient fallback backgrounds
|
- Image handling with gradient fallback backgrounds
|
||||||
- Status badges with proper color coding (operating, closed_temporarily, closed_permanently, under_construction)
|
- Status badges with proper color coding (operating, closed_temporarily, closed_permanently, under_construction)
|
||||||
- Ride name with link to detail page
|
- Ride name with conditional linking based on slug availability
|
||||||
- Category and park information display
|
- Category and park information display
|
||||||
- Statistics grid for height, speed, capacity, duration
|
- Statistics grid for height, speed, capacity, duration
|
||||||
- Special features badges (inversions, launches, track_type)
|
- Special features badges (inversions, launches, track_type)
|
||||||
- Opening date and manufacturer/designer information
|
- Opening date and manufacturer/designer information
|
||||||
- Responsive design with hover effects
|
- Responsive design with hover effects
|
||||||
- Modern Tailwind styling and animations
|
- Modern Tailwind styling and animations
|
||||||
|
- Backwards compatibility with existing usage
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
|
|
||||||
<c-vars
|
<c-vars
|
||||||
ride=""
|
ride=""
|
||||||
|
url_variant="global"
|
||||||
class=""
|
class=""
|
||||||
fallback_gradient="from-blue-500 to-purple-600"
|
fallback_gradient="from-blue-500 to-purple-600"
|
||||||
/>
|
/>
|
||||||
@@ -94,10 +110,21 @@ Features:
|
|||||||
<!-- Name and category -->
|
<!-- Name and category -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-1">
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-1">
|
||||||
|
{% comment %}Robust URL generation with missing slug handling{% endcomment %}
|
||||||
|
{% if url_variant == 'park' and ride.park and ride.park.slug and ride.slug %}
|
||||||
|
<a href="{% url 'parks:rides:ride_detail' ride.park.slug ride.slug %}"
|
||||||
|
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||||
|
{{ ride.name }}
|
||||||
|
</a>
|
||||||
|
{% elif url_variant == 'global' and ride.slug %}
|
||||||
<a href="{% url 'rides:ride_detail' ride.slug %}"
|
<a href="{% url 'rides:ride_detail' ride.slug %}"
|
||||||
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
|
||||||
{{ ride.name }}
|
{{ ride.name }}
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{% comment %}No valid URL can be generated - render as plain text{% endcomment %}
|
||||||
|
{{ ride.name }}
|
||||||
|
{% endif %}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
<div class="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
||||||
<span class="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300 mr-2">
|
<span class="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300 mr-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user