add open position system
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 48s
Tests / PHPUnit (push) Successful in 1m29s

This commit is contained in:
root
2026-09-02 00:53:55 -04:00
parent 5b11e2d859
commit dbfd72c2f9
24 changed files with 1627 additions and 47 deletions
+115 -4
View File
@@ -198,6 +198,74 @@
background-color: var(--accent);
}
/* Open positions banner */
.careers-ticker {
display: block;
background-color: var(--primary-dark);
color: var(--paper);
text-decoration: none;
overflow: hidden;
border-top: 1px solid rgba(243, 239, 227, 0.14);
border-bottom: 1px solid rgba(243, 239, 227, 0.14);
}
.careers-ticker:hover,
.careers-ticker:focus {
color: var(--paper);
}
.ticker-track {
display: flex;
width: max-content;
animation: ticker-scroll 10s linear infinite;
}
.careers-ticker:hover .ticker-track,
.careers-ticker:focus .ticker-track,
.careers-ticker:focus-within .ticker-track {
animation-play-state: paused;
}
.ticker-group {
display: flex;
align-items: center;
min-width: max-content;
}
.ticker-label,
.ticker-item {
display: inline-flex;
align-items: center;
min-height: 54px;
white-space: nowrap;
}
.ticker-label {
padding: 0 1.5rem;
font-weight: 700;
color: var(--accent-soft);
}
.ticker-item {
gap: 0.5rem;
padding: 0 1.75rem;
border-left: 1px solid rgba(243, 239, 227, 0.16);
}
.ticker-title {
font-weight: 700;
}
.ticker-meta {
color: #DCE6DD;
font-size: 0.9rem;
}
@keyframes ticker-scroll {
from { transform: translateX(100vw); }
to { transform: translateX(-50%); }
}
@media (max-width: 992px) {
.carousel-item { height: 480px; }
.carousel-caption { max-width: 78%; padding: 1.5rem; bottom: 8%; }
@@ -209,6 +277,9 @@
.carousel-caption { left: 5%; right: 5%; max-width: none; padding: 1.1rem 1.25rem; bottom: 6%; }
.carousel-caption h1 { font-size: 1.2rem; }
.carousel-caption p { font-size: 0.85rem; }
.ticker-track { animation-duration: 10s; }
.ticker-label, .ticker-item { min-height: 48px; }
.ticker-item { padding: 0 1.25rem; }
}
/* Join line */
@@ -506,6 +577,46 @@
</div>
<!-- Carousel End -->
<?php
$tickerPositions = !empty($openPositions) && is_array($openPositions) ? $openPositions : [];
$tickerItems = [];
foreach ($tickerPositions as $position) {
$meta = array_filter([
$position['department'] ?? '',
$position['location'] ?? '',
$position['employment_type'] ?? '',
], static fn ($value) => trim((string) $value) !== '');
$tickerItems[] = [
'title' => (string) ($position['title'] ?? 'Open Position'),
'meta' => implode(' · ', $meta),
];
}
if ($tickerItems === []) {
$tickerItems[] = [
'title' => 'Volunteer opportunities',
'meta' => 'See current openings',
];
}
?>
<a class="careers-ticker" href="<?= site_url('careers') ?>" aria-label="View open volunteer positions">
<div class="ticker-track">
<?php for ($copy = 0; $copy < 2; $copy++): ?>
<div class="ticker-group" <?= $copy === 1 ? 'aria-hidden="true"' : '' ?>>
<span class="ticker-label">Now recruiting volunteers</span>
<?php foreach ($tickerItems as $item): ?>
<span class="ticker-item">
<span class="ticker-title"><?= esc($item['title']) ?></span>
<?php if ($item['meta'] !== ''): ?>
<span class="ticker-meta"><?= esc($item['meta']) ?></span>
<?php endif; ?>
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</span>
<?php endforeach; ?>
</div>
<?php endfor; ?>
</div>
</a>
<!-- Join line -->
<div class="join-strip">
<a href="<?= base_url('account_creation_guide.pdf') ?>" target="_blank">
@@ -515,7 +626,7 @@
<!-- Statistics Start -->
<div class="stats-band section-tight">
<div class="container-narrow" data-dashboard-endpoint="/api/administrator/dashboard">
<div class="container-narrow" data-dashboard-endpoint="<?= site_url('api/administrator/dashboard') ?>">
<h2>Active Participants</h2>
<div class="stats-row">
<div class="stat-cell">
@@ -644,7 +755,7 @@
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const container = document.querySelector('.stats-band[data-dashboard-endpoint]');
const container = document.querySelector('.stats-band [data-dashboard-endpoint]');
if (!container) return;
const endpoint = container.dataset.dashboardEndpoint;
const statElements = container.querySelectorAll('[data-stat]');
@@ -666,7 +777,7 @@
const counts = payload && typeof payload === 'object' && payload.counts ? payload.counts : {};
statElements.forEach(function (element) {
const key = element.dataset.stat;
const value = counts[key];
const value = Number(counts[key]);
element.textContent = Number.isFinite(value) ? numberFormatter.format(value) : '—';
});
})
@@ -685,4 +796,4 @@
</script>
</body>
</html>
</html>