From ffebd5ce016f278619ab72eef76e992890ca9c45 Mon Sep 17 00:00:00 2001
From: pac7 <47831526-pac7@users.noreply.replit.com>
Date: Mon, 22 Sep 2025 03:35:47 +0000
Subject: [PATCH] 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
---
.replit | 2 +-
static/css/tailwind.css | 72 +++++++++++++++++++++++++++++++++
templates/cotton/ride_card.html | 41 +++++++++++++++----
3 files changed, 107 insertions(+), 8 deletions(-)
diff --git a/.replit b/.replit
index 1a513a3c..5bd91547 100644
--- a/.replit
+++ b/.replit
@@ -55,7 +55,7 @@ localPort = 5000
externalPort = 80
[[ports]]
-localPort = 35685
+localPort = 37689
externalPort = 3002
[[ports]]
diff --git a/static/css/tailwind.css b/static/css/tailwind.css
index 9e447eeb..590d1485 100644
--- a/static/css/tailwind.css
+++ b/static/css/tailwind.css
@@ -410,6 +410,9 @@
.top-0 {
top: calc(var(--spacing) * 0);
}
+ .top-1 {
+ top: calc(var(--spacing) * 1);
+ }
.top-1\/2 {
top: calc(1/2 * 100%);
}
@@ -449,6 +452,9 @@
.left-0 {
left: calc(var(--spacing) * 0);
}
+ .left-1 {
+ left: calc(var(--spacing) * 1);
+ }
.left-1\/2 {
left: calc(1/2 * 100%);
}
@@ -527,6 +533,9 @@
max-width: 96rem;
}
}
+ .-mx-1 {
+ margin-inline: calc(var(--spacing) * -1);
+ }
.-mx-1\.5 {
margin-inline: calc(var(--spacing) * -1.5);
}
@@ -545,6 +554,9 @@
.mx-auto {
margin-inline: auto;
}
+ .-my-1 {
+ margin-block: calc(var(--spacing) * -1);
+ }
.-my-1\.5 {
margin-block: calc(var(--spacing) * -1.5);
}
@@ -554,6 +566,9 @@
.my-auto {
margin-block: auto;
}
+ .mt-0 {
+ margin-top: calc(var(--spacing) * 0);
+ }
.mt-0\.5 {
margin-top: calc(var(--spacing) * 0.5);
}
@@ -626,6 +641,9 @@
.mb-12 {
margin-bottom: calc(var(--spacing) * 12);
}
+ .-ml-0 {
+ margin-left: calc(var(--spacing) * -0);
+ }
.-ml-0\.5 {
margin-left: calc(var(--spacing) * -0.5);
}
@@ -797,6 +815,9 @@
.min-h-screen {
min-height: 100vh;
}
+ .w-1 {
+ width: calc(var(--spacing) * 1);
+ }
.w-1\/2 {
width: calc(1/2 * 100%);
}
@@ -932,6 +953,13 @@
.grow {
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 {
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
@@ -948,6 +976,10 @@
--tw-translate-x: 100%;
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 {
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
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)));
}
}
+ .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 {
:where(& > :not(:last-child)) {
--tw-space-x-reverse: 0;
@@ -1394,6 +1433,9 @@
.bg-\[\#5865F2\] {
background-color: #5865F2;
}
+ .bg-accent {
+ background-color: var(--color-accent);
+ }
.bg-accent\/10 {
background-color: color-mix(in srgb, #8b5cf6 10%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1442,6 +1484,9 @@
.bg-blue-600 {
background-color: var(--color-blue-600);
}
+ .bg-blue-900 {
+ background-color: var(--color-blue-900);
+ }
.bg-blue-900\/40 {
background-color: color-mix(in srgb, oklch(37.9% 0.146 265.522) 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1496,6 +1541,9 @@
.bg-green-600 {
background-color: var(--color-green-600);
}
+ .bg-green-900 {
+ background-color: var(--color-green-900);
+ }
.bg-green-900\/40 {
background-color: color-mix(in srgb, oklch(39.3% 0.095 152.535) 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1550,6 +1598,9 @@
.bg-red-600 {
background-color: var(--color-red-600);
}
+ .bg-red-900 {
+ background-color: var(--color-red-900);
+ }
.bg-red-900\/40 {
background-color: color-mix(in srgb, oklch(39.6% 0.141 25.723) 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1607,6 +1658,9 @@
.bg-yellow-600 {
background-color: var(--color-yellow-600);
}
+ .bg-yellow-900 {
+ background-color: var(--color-yellow-900);
+ }
.bg-yellow-900\/40 {
background-color: color-mix(in srgb, oklch(42.1% 0.095 57.708) 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1625,6 +1679,10 @@
--tw-gradient-position: to top in oklab;
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 {
--tw-gradient-from: color-mix(in srgb, #000 60%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1685,6 +1743,10 @@
--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));
}
+ .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 {
--tw-gradient-from: color-mix(in srgb, #e11d48 20%, transparent);
@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-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 {
--tw-gradient-to: color-mix(in srgb, #8b5cf6 20%, transparent);
@supports (color: color-mix(in lab, red, red)) {
@@ -1849,6 +1915,9 @@
.px-8 {
padding-inline: calc(var(--spacing) * 8);
}
+ .py-0 {
+ padding-block: calc(var(--spacing) * 0);
+ }
.py-0\.5 {
padding-block: calc(var(--spacing) * 0.5);
}
@@ -2185,6 +2254,9 @@
.italic {
font-style: italic;
}
+ .underline {
+ text-decoration-line: underline;
+ }
.underline-offset-4 {
text-underline-offset: 4px;
}
diff --git a/templates/cotton/ride_card.html b/templates/cotton/ride_card.html
index 0e056337..ffce1f60 100644
--- a/templates/cotton/ride_card.html
+++ b/templates/cotton/ride_card.html
@@ -1,45 +1,61 @@
{% comment %}
Ride Card Component - Django Cotton Version
-A comprehensive ride card component with image handling, status badges, and feature displays.
-Includes all ride statistics, special features, and manufacturer information.
+A comprehensive ride card component with image handling, status badges, feature displays,
+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:
-Basic usage:
+Basic usage (default global URL pattern):