Compare commits

...

3 Commits

Author SHA1 Message Date
jamesp 6a9daeab0d More mobile tidy 2026-06-26 08:21:24 -04:00
jamesp 730eb7758a Mobile tidy-ups 2026-06-26 08:21:09 -04:00
jamesp c43e4acc32 Mobile price list 2026-06-26 08:13:52 -04:00
4 changed files with 213 additions and 27 deletions
+5 -2
View File
@@ -65,7 +65,7 @@ function formatVatLabel(value: unknown): string {
} }
.fuel-service-notes { .fuel-service-notes {
margin: 0 0 1.1rem; margin: 0 0 1.9rem;
} }
.fuel-service-notes p { .fuel-service-notes p {
@@ -77,7 +77,10 @@ function formatVatLabel(value: unknown): string {
} }
.fuel-contact-link { .fuel-contact-link {
margin-top: 0.35rem; display: flex;
width: fit-content;
margin-top: 0.55rem;
margin-inline: auto;
} }
.fuel-more-info { .fuel-more-info {
+110 -19
View File
@@ -46,6 +46,11 @@ const additionalCharges = [
['Runway closure', '£50', 'At management discretion following incident or accident.'], ['Runway closure', '£50', 'At management discretion following incident or accident.'],
['Drones', '£25', 'Commercial drones need 2 days notice before flight and a permit.'], ['Drones', '£25', 'Commercial drones need 2 days notice before flight and a permit.'],
]; ];
const gaHeaders = ['Type', 'Landing fee', 'Daytime parking', 'Overnight parking outside', 'Overnight parking hangar'];
const touchAndGoHeaders = ['Type', 'Single', 'Unlimited'];
const businessHeaders = ['MTOW', 'Landing fee', 'Daytime parking', 'Overnight parking'];
const additionalHeaders = ['Charge', 'Price', 'Notes'];
--- ---
<BaseLayout title="Fees and Charges" description="Swansea Airport landing, parking, handling, and related charges."> <BaseLayout title="Fees and Charges" description="Swansea Airport landing, parking, handling, and related charges.">
@@ -60,17 +65,13 @@ const additionalCharges = [
<table class="fee-table"> <table class="fee-table">
<thead> <thead>
<tr> <tr>
<th scope="col">Type</th> {gaHeaders.map((header) => <th scope="col">{header}</th>)}
<th scope="col">Landing fee</th>
<th scope="col">Daytime parking</th>
<th scope="col">Overnight parking outside</th>
<th scope="col">Overnight parking hangar</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{gaCharges.map((row) => ( {gaCharges.map((row) => (
<tr> <tr>
{row.map((cell) => <td>{cell}</td>)} {row.map((cell, index) => <td data-label={gaHeaders[index]}>{cell}</td>)}
</tr> </tr>
))} ))}
</tbody> </tbody>
@@ -84,15 +85,13 @@ const additionalCharges = [
<table class="fee-table"> <table class="fee-table">
<thead> <thead>
<tr> <tr>
<th scope="col">Type</th> {touchAndGoHeaders.map((header) => <th scope="col">{header}</th>)}
<th scope="col">Single</th>
<th scope="col">Unlimited</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{touchAndGoCharges.map((row) => ( {touchAndGoCharges.map((row) => (
<tr> <tr>
{row.map((cell) => <td>{cell}</td>)} {row.map((cell, index) => <td data-label={touchAndGoHeaders[index]}>{cell}</td>)}
</tr> </tr>
))} ))}
</tbody> </tbody>
@@ -119,16 +118,13 @@ const additionalCharges = [
<table class="fee-table"> <table class="fee-table">
<thead> <thead>
<tr> <tr>
<th scope="col">MTOW</th> {businessHeaders.map((header) => <th scope="col">{header}</th>)}
<th scope="col">Landing fee</th>
<th scope="col">Daytime parking</th>
<th scope="col">Overnight parking</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{businessCharges.map((row) => ( {businessCharges.map((row) => (
<tr> <tr>
{row.map((cell) => <td>{cell}</td>)} {row.map((cell, index) => <td data-label={businessHeaders[index]}>{cell}</td>)}
</tr> </tr>
))} ))}
</tbody> </tbody>
@@ -149,15 +145,13 @@ const additionalCharges = [
<table class="fee-table"> <table class="fee-table">
<thead> <thead>
<tr> <tr>
<th scope="col">Charge</th> {additionalHeaders.map((header) => <th scope="col">{header}</th>)}
<th scope="col">Price</th>
<th scope="col">Notes</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{additionalCharges.map((row) => ( {additionalCharges.map((row) => (
<tr> <tr>
{row.map((cell) => <td>{cell}</td>)} {row.map((cell, index) => <td data-label={additionalHeaders[index]}>{cell}</td>)}
</tr> </tr>
))} ))}
</tbody> </tbody>
@@ -236,4 +230,101 @@ const additionalCharges = [
.fee-section ul { .fee-section ul {
margin-top: 0.6rem; margin-top: 0.6rem;
} }
@media (max-width: 700px) {
.fees-page {
gap: 1rem;
}
.fee-section {
padding-block: 0.35rem;
}
.fee-table-wrap {
overflow: visible;
}
.fee-table,
.fee-table tbody,
.fee-table tr,
.fee-table td {
display: block;
width: 100%;
}
.fee-table {
min-width: 0;
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.fee-table-wrap.compact .fee-table {
min-width: 0;
}
.fee-table thead {
display: none;
}
.fee-table tbody {
display: grid;
gap: 0.75rem;
}
.fee-table tr {
overflow: hidden;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: rgba(255, 255, 255, 0.88);
box-shadow: 0 10px 22px rgba(16, 34, 51, 0.07);
}
.fee-table tbody tr:nth-child(even) {
background: rgba(255, 255, 255, 0.88);
}
.fee-table td {
display: grid;
grid-template-columns: minmax(8rem, 0.9fr) minmax(0, 1.1fr);
gap: 0.75rem;
padding: 0.68rem 0.85rem;
border-bottom: 1px solid var(--line);
overflow-wrap: anywhere;
}
.fee-table td:first-child {
display: block;
padding: 0.85rem;
background: linear-gradient(180deg, rgba(11, 79, 122, 0.12), rgba(29, 118, 184, 0.07));
color: var(--text);
font-weight: 800;
}
.fee-table td:first-child::before {
content: none;
}
.fee-table td:last-child {
border-bottom: 0;
}
.fee-table td::before {
content: attr(data-label);
color: var(--brand);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.04em;
line-height: 1.25;
text-transform: uppercase;
}
}
@media (max-width: 420px) {
.fee-table td {
grid-template-columns: 1fr;
gap: 0.2rem;
}
}
</style> </style>
+6 -5
View File
@@ -5,6 +5,7 @@ import { getFuelPrices } from '../lib/directus';
import { site } from '../lib/site'; import { site } from '../lib/site';
const runwayPattern = /^Runway\s+(\d+)\s+-\s+([^\s]+)\s+LDA\s+\(([^)]+)\)\s+Code\s+(\d+)\s+\(([^)]+)\)$/; const runwayPattern = /^Runway\s+(\d+)\s+-\s+([^\s]+)\s+LDA\s+\(([^)]+)\)\s+Code\s+(\d+)\s+\(([^)]+)\)$/;
const runwayHeaders = ['Runway', 'LDA', 'Surface', 'Code', 'Circuits'];
const runwayRows = site.runwayFacts const runwayRows = site.runwayFacts
.map((fact) => { .map((fact) => {
@@ -114,11 +115,11 @@ When the Tower is unavailable, this will be NOTAMed and blind calls to Swansea T
<tbody> <tbody>
{runwayRows.map((runway) => ( {runwayRows.map((runway) => (
<tr> <tr>
<td>{runway.runway}</td> <td data-label={runwayHeaders[0]}>{runway.runway}</td>
<td>{runway.lda}</td> <td data-label={runwayHeaders[1]}>{runway.lda}</td>
<td>{runway.surface}</td> <td data-label={runwayHeaders[2]}>{runway.surface}</td>
<td>{runway.code}</td> <td data-label={runwayHeaders[3]}>{runway.code}</td>
<td>{runway.circuits}</td> <td data-label={runwayHeaders[4]}>{runway.circuits}</td>
</tr> </tr>
))} ))}
</tbody> </tbody>
+92 -1
View File
@@ -971,6 +971,97 @@ section {
} }
.runway-facts-table { .runway-facts-table {
min-width: 38rem; min-width: 0;
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.runway-table-wrap {
overflow: visible;
}
.runway-facts-table,
.runway-facts-table tbody,
.runway-facts-table tr,
.runway-facts-table td {
display: block;
width: 100%;
}
.runway-facts-table thead {
display: none;
}
.runway-facts-table tbody {
display: grid;
gap: 0.75rem;
}
.runway-facts-table tr {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
padding: 0.75rem;
background: rgba(255, 255, 255, 0.88);
box-shadow: 0 10px 22px rgba(16, 34, 51, 0.07);
}
.runway-facts-table tbody tr:nth-child(even),
.runway-facts-table tbody tr:hover {
background: rgba(255, 255, 255, 0.88);
}
.runway-facts-table td {
display: grid;
gap: 0.18rem;
min-height: 3.4rem;
padding: 0.62rem 0.7rem;
border: 1px solid rgba(16, 34, 51, 0.08);
border-radius: 0.7rem;
background: rgba(255, 255, 255, 0.72);
font-weight: 800;
line-height: 1.2;
white-space: normal;
}
.runway-facts-table td:first-child {
display: flex;
align-items: center;
gap: 0.45rem;
grid-column: 1 / -1;
min-height: 0;
padding: 0.85rem;
border: 0;
background: linear-gradient(180deg, rgba(11, 79, 122, 0.12), rgba(29, 118, 184, 0.07));
color: var(--text);
font-size: 1.08rem;
font-weight: 800;
}
.runway-facts-table td:first-child::before {
content: 'Runway';
color: var(--brand);
font-size: 0.78rem;
font-weight: 800;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.runway-facts-table td:last-child {
border-bottom: 1px solid rgba(16, 34, 51, 0.08);
}
.runway-facts-table td::before {
content: attr(data-label);
color: var(--brand);
font-size: 0.68rem;
font-weight: 800;
letter-spacing: 0.04em;
line-height: 1;
text-transform: uppercase;
} }
} }