Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions website/public/assets/css/pages/city-hub.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* City hub data-preview layout — extracted from the Bengaluru hub so every
city hub can share it. Communities/Stories/Map preview sections. */

.hub-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
max-width: 1200px;
margin: 0 auto;
}
.hub-section {
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
padding: 1.25rem;
overflow: hidden;
}
.hub-section-wide { grid-column: 1 / -1; }
.hub-section-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 1rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid rgba(0,0,0,0.06);
}
.hub-section-header h3 {
margin: 0;
font-size: 1rem;
color: #2F4A2C;
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.hub-count {
font-size: 0.85rem;
font-weight: 600;
color: #B9C98A;
}
.hub-see-all {
font-size: 0.8rem;
font-weight: 600;
color: #2F4A2C;
text-decoration: none;
white-space: nowrap;
display: flex;
align-items: center;
gap: 4px;
opacity: 0.6;
transition: opacity 0.2s;
}
.hub-see-all:hover { opacity: 1; }

.hub-preview-list { display: flex; flex-direction: column; gap: 4px; }
.hub-preview-item {
display: flex;
flex-direction: column;
padding: 8px 12px;
border-radius: 8px;
text-decoration: none;
color: inherit;
transition: background 0.2s;
}
.hub-preview-item:hover { background: rgba(185,201,138,0.1); }
.hub-preview-item strong { font-size: 0.9rem; color: #2B2B2B; }
.hub-preview-meta { font-size: 0.75rem; color: #999; }

.hub-sector-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.hub-sector-card {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-radius: 8px;
text-decoration: none;
color: inherit;
transition: background 0.2s;
border: 1px solid rgba(0,0,0,0.04);
}
.hub-sector-card:hover { background: rgba(185,201,138,0.1); }
.hub-sector-card i { font-size: 1.2rem; color: #2F4A2C; min-width: 24px; text-align: center; }
.hub-sector-card strong { font-size: 0.85rem; color: #2B2B2B; display: block; }
.hub-sector-card span { font-size: 0.72rem; color: #999; line-height: 1.3; }

.hub-map-preview {
display: block;
border-radius: 8px;
overflow: hidden;
background: #FAF6E8;
text-align: center;
}
.hub-loading { text-align: center; color: #999; padding: 1rem; font-size: 0.85rem; }

/* Empty state with a call-to-action (used when a city has no data yet). */
.hub-empty {
text-align: center;
color: #666;
padding: 1.25rem 1rem;
font-size: 0.9rem;
}
.hub-empty a {
display: inline-flex;
align-items: center;
gap: 6px;
margin-top: 0.6rem;
font-weight: 600;
color: #2F4A2C;
text-decoration: none;
}
.hub-empty a:hover { text-decoration: underline; }

@media (max-width: 768px) {
.hub-grid { grid-template-columns: 1fr; }
.hub-sector-grid { grid-template-columns: 1fr; }
}
31 changes: 31 additions & 0 deletions website/public/assets/js/pages/city-hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,37 @@
if (cityCommunities.length > 0) commStat.classList.remove('zero');
}

const esc = (s) => String(s == null ? '' : s)
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;').replace(/'/g, '&#039;');

// Communities preview list (Bengaluru-style hub layout).
const hubCommCount = document.getElementById('hubCommCount');
if (hubCommCount) hubCommCount.textContent = cityCommunities.length;
const hubCommunities = document.getElementById('hubCommunities');
if (hubCommunities) {
hubCommunities.innerHTML = cityCommunities.length > 0
? cityCommunities.slice(0, 4).map((c) =>
'<a href="/communities/" class="hub-preview-item">' +
'<strong>' + esc(c.name) + '</strong>' +
'<span class="hub-preview-meta">' + esc((c.themes || []).slice(0, 2).join(', ')) + '</span></a>'
).join('')
: '<div class="hub-empty">No communities here yet.' +
'<a href="/join/"><i class="fa-solid fa-user-plus"></i> Join as a community</a></div>';
}

// Stories preview list.
const hubStories = document.getElementById('hubStories');
if (hubStories) {
hubStories.innerHTML = cityStories.length > 0
? cityStories.slice(0, 3).map((s) =>
'<a href="/cities/' + slug + '/stories/?story=' + encodeURIComponent(s.slug) + '" class="hub-preview-item">' +
'<strong>' + esc(s.title) + '</strong>' +
'<span class="hub-preview-meta">' + esc(s.community || s.location || '') + '</span></a>'
).join('')
: '<div class="hub-empty">No stories here yet.</div>';
}

// Community Stories card -> Live when the city has stories.
const storiesCard = document.querySelector('[data-feature="stories"]');
if (storiesCard && cityStories.length > 0) {
Expand Down
105 changes: 24 additions & 81 deletions website/public/cities/chennai/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<meta name="description" content="Communities, solution providers, and ward-level climate data across Chennai's 200 GCC wards.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="/assets/css/main.css">
<link rel="stylesheet" href="/assets/css/pages/city-hub.css">
<link rel="stylesheet" href="/assets/chat/chat.css">
<link rel="stylesheet" href="/assets/i18n/language-selector.css">
<style>
Expand Down Expand Up @@ -378,96 +379,38 @@ <h2 data-i18n="cityHub.chennai.exploreTitle">Explore Chennai</h2>
<p data-i18n="cityHub.chennai.exploreSubtitle">Ward-level map available now. Community and provider directories coming soon.</p>
</div>

<div class="feature-grid">
<!-- Ward Map (Available) -->
<div class="feature-card-large">
<div class="feature-header">
<div class="feature-icon-large">
<i class="fa-solid fa-map" style="color: #B9C98A !important;"></i>
</div>
<div class="feature-info">
<h3 data-i18n="cityHub.features.map.title">Ward-Level Map</h3>
<span class="feature-status-badge live">
<i class="fa-solid fa-check-circle"></i> <span data-i18n="cityHub.features.map.statusLive">Live</span>
</span>
</div>
<div class="hub-grid">
<!-- Communities Preview (populated by city-hub.js) -->
<div class="hub-section">
<div class="hub-section-header">
<h3><img src="/assets/images/icons/community.svg" alt="" style="width:24px;height:24px;vertical-align:middle;"> <span data-i18n="cityHub.features.communities.title">Communities</span></h3>
<span class="hub-count" id="hubCommCount">-</span>
<a href="/communities/" class="hub-see-all">See all <i class="fa-solid fa-arrow-right"></i></a>
</div>
<p class="feature-description" data-i18n="cityHub.features.map.description" data-i18n-params='{"wardCount":"200"}'>
Explore all 200 electoral wards with interactive boundaries. View ward demographics and geographical data across Chennai.
</p>
<div class="feature-action">
<a href="/cities/chennai/map/" class="btn btn-primary">
<span data-i18n="cityHub.features.map.button">View Map</span> <i class="fa-solid fa-arrow-right"></i>
</a>
<div class="hub-preview-list" id="hubCommunities">
<div class="hub-loading">Loading...</div>
</div>
</div>

<!-- Communities (Coming Soon) -->
<div class="feature-card-large coming-soon">
<div class="feature-header">
<div class="feature-icon-large">
<img src="/assets/images/icons/community.svg" alt="" style="width:20px;height:20px;">
</div>
<div class="feature-info">
<h3 data-i18n="cityHub.features.communities.title">Communities</h3>
<span class="feature-status-badge coming-soon">
<i class="fa-solid fa-clock"></i> <span data-i18n="cityHub.features.statusComingSoon">Coming Soon</span>
</span>
</div>
<!-- Stories Preview (populated by city-hub.js) -->
<div class="hub-section">
<div class="hub-section-header">
<h3><img src="/assets/images/icons/story.svg" alt="" style="width:24px;height:24px;vertical-align:middle;"> <span data-i18n="cityHub.features.stories.title">Community Stories</span></h3>
<a href="/cities/chennai/stories/" class="hub-see-all">Read all <i class="fa-solid fa-arrow-right"></i></a>
</div>
<p class="feature-description" data-i18n="cityHub.comingSoonCallout.description">
Community directory for Chennai is under development. Help us build the network by joining as a community.
</p>
<div class="feature-action">
<button class="btn" style="background: var(--color-text-lighter); cursor: not-allowed;" disabled>
<span data-i18n="cityHub.comingSoonCallout.comingSoonButton">Coming Soon</span>
</button>
<div class="hub-preview-list" id="hubStories">
<div class="hub-loading">Loading...</div>
</div>
</div>


<!-- Community Stories (state set dynamically by city-hub.js) -->
<div class="feature-card-large coming-soon" data-feature="stories">
<div class="feature-header">
<div class="feature-icon-large">
<img src="/assets/images/icons/story.svg" alt="" style="width:20px;height:20px;">
</div>
<div class="feature-info">
<h3 data-i18n="cityHub.features.stories.title">Community Stories</h3>
<span class="feature-status-badge coming-soon">
<i class="fa-solid fa-clock"></i> <span data-i18n="cityHub.features.statusComingSoon">Coming Soon</span>
</span>
</div>
<!-- Map Preview -->
<div class="hub-section hub-section-wide">
<div class="hub-section-header">
<h3><img src="/assets/images/icons/location.svg" alt="" style="width:24px;height:24px;vertical-align:middle;"> <span data-i18n="cityHub.features.map.title">Ward-Level Map</span></h3>
<a href="/cities/chennai/map/" class="hub-see-all">View map <i class="fa-solid fa-arrow-right"></i></a>
</div>
<p class="feature-description" data-i18n="cityHub.features.stories.comingSoonDescription">
Community stories for this city are under development. Real stories of neighbourhood transformation coming soon.
</p>
<div class="feature-action">
<button class="btn" style="background: var(--color-text-lighter); cursor: not-allowed;" disabled>
<span data-i18n="cityHub.comingSoonCallout.comingSoonButton">Coming Soon</span>
</button>
</div>
</div>
</div>

<!-- Coming Soon Callout -->
<div class="coming-soon-callout">
<img src="/assets/images/icons/plant.svg" alt="" aria-hidden="true" style="width: 64px; height: 64px; margin-bottom: var(--space-md);">
<h3 data-i18n="cityHub.comingSoonCallout.title">Chennai Data Coming Soon</h3>
<p data-i18n="cityHub.comingSoonCallout.description">
We're currently building the Chennai directory. Help us grow the network by registering your community or organization.
</p>
<p style="font-weight: 600;">
<img src="/assets/images/icons/community.svg" alt="" style="width:20px;height:20px;"> <span data-i18n="cityHub.comingSoonCallout.communityDirectory">Community Directory</span><br>
<i class="fa-solid fa-building"></i> <span data-i18n="cityHub.comingSoonCallout.providerNetwork">Solution Provider Network</span><br>
<img src="/assets/images/icons/conservation.svg" alt="" style="width:20px;height:20px;"> <span data-i18n="cityHub.comingSoonCallout.climateAction">Climate Action Dashboard</span>
</p>
<div class="cta-buttons">
<a href="/join/" class="btn btn-primary">
<i class="fa-solid fa-user-plus"></i> <span data-i18n="cityHub.comingSoonCallout.joinCommunity">Join as Community</span>
</a>
<a href="/join/" class="btn btn-secondary">
<i class="fa-solid fa-building-user"></i> <span data-i18n="cityHub.comingSoonCallout.joinProvider">Join as Provider</span>
<a href="/cities/chennai/map/" class="hub-map-preview" id="hubMap">
<img src="/assets/images/cities/chennai.svg" alt="Chennai ward map" style="width:100%; height:200px; object-fit: contain; opacity: 0.7;">
</a>
</div>
</div>
Expand Down
Loading