fix(seo): comprehensive SEO improvements per expert audit
CI Pipeline / backend-test (pull_request) Successful in 4m20s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / frontend-build (pull_request) Failing after 29s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / backend-test (push) Successful in 4m22s
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / frontend-build (push) Failing after 28s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 1s
CI Pipeline / backend-test (pull_request) Successful in 4m20s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / frontend-build (pull_request) Failing after 29s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / backend-test (push) Successful in 4m22s
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / frontend-build (push) Failing after 28s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 1s
- Add public/robots.txt (allow all, disallow /admin and /login, reference sitemap) - Add public/sitemap.xml (5 public routes with change frequencies and priorities) - Fix heading hierarchy: h2 -> h1 on about, schedule, events, contact pages - Remove dead footer href="#" links: - Volunteer/Corporate Giving/Planned Giving -> routerLink to /contact with subject query param - Social media links -> conditional on config().social_* fields (hidden when empty) - Fix logo ARIA: add aria-hidden="true" to decorative logo in about page divider - Add social_facebook, social_twitter, social_instagram, social_youtube to: - StationConfig DB model + startup migration - StationConfigResponse and StationConfigUpdate schemas - Frontend StationConfig TypeScript interface - Fix events "Learn More" dead link -> routerLink to /contact
This commit is contained in:
1 parent
65af2824a9
commit
bea1c97e88
28 files changed
+83
-14
No files matched your search
@@ -2,7 +2,7 @@ name: CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop, feature/tests-and-ci, feature/multi-admin-roles]
|
||||
branches: [main, develop, feature/tests-and-ci, feature/multi-admin-roles, fix/seo-improvements]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -78,6 +78,11 @@ def _migrate_add_missing_columns(sync_conn):
|
||||
("station_config", "color_black", sa.String(7), "#1a1816"),
|
||||
# Multi-admin support: password_hash (nullable — existing rows stay NULL)
|
||||
("users", "password_hash", sa.String(255), None),
|
||||
# Social media columns
|
||||
("station_config", "social_facebook", sa.String(500), ""),
|
||||
("station_config", "social_twitter", sa.String(500), ""),
|
||||
("station_config", "social_instagram", sa.String(500), ""),
|
||||
("station_config", "social_youtube", sa.String(500), ""),
|
||||
]
|
||||
|
||||
# Determine dialect
|
||||
|
||||
@@ -97,6 +97,12 @@ class StationConfig(Base):
|
||||
# Donation
|
||||
donation_url = Column(String(500), nullable=False, default="")
|
||||
|
||||
# Social media
|
||||
social_facebook = Column(String(500), nullable=False, default="")
|
||||
social_twitter = Column(String(500), nullable=False, default="")
|
||||
social_instagram = Column(String(500), nullable=False, default="")
|
||||
social_youtube = Column(String(500), nullable=False, default="")
|
||||
|
||||
# Stream
|
||||
stream_url = Column(String(500), nullable=False, default="")
|
||||
stream_metadata_url = Column(String(500), nullable=False, default="")
|
||||
|
||||
@@ -78,6 +78,11 @@ class StationConfigResponse(BaseModel):
|
||||
play_store_icon_url: str
|
||||
play_store_url: str
|
||||
app_store_embed_html: str
|
||||
# Social media
|
||||
social_facebook: str
|
||||
social_twitter: str
|
||||
social_instagram: str
|
||||
social_youtube: str
|
||||
# Page content
|
||||
hero_subtitle: str
|
||||
about_intro: str
|
||||
@@ -129,6 +134,11 @@ class StationConfigUpdate(BaseModel):
|
||||
play_store_icon_url: Optional[str] = None
|
||||
play_store_url: Optional[str] = None
|
||||
app_store_embed_html: Optional[str] = None
|
||||
# Social media
|
||||
social_facebook: Optional[str] = None
|
||||
social_twitter: Optional[str] = None
|
||||
social_instagram: Optional[str] = None
|
||||
social_youtube: Optional[str] = None
|
||||
# Page content
|
||||
hero_subtitle: Optional[str] = None
|
||||
about_intro: Optional[str] = None
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Disallow: /admin
|
||||
Disallow: /login
|
||||
|
||||
Sitemap: https://kmountainflower.org/sitemap.xml
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://kmountainflower.org/</loc>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://kmountainflower.org/about</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://kmountainflower.org/schedule</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://kmountainflower.org/events</loc>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://kmountainflower.org/contact</loc>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.5</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Intro -->
|
||||
<div class="about-intro">
|
||||
<img [src]="resolveImageUrl(config().hero_icon_url)" alt="" class="about-flower-decor" aria-hidden="true">
|
||||
<h2>About <span class="text-accent">{{ config().name_primary }} {{ config().name_secondary }}</span></h2>
|
||||
<h1>About <span class="text-accent">{{ config().name_primary }} {{ config().name_secondary }}</span></h1>
|
||||
<p class="section-intro">{{ config().about_intro }}</p>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
@if (config().donation_url) {
|
||||
<div class="about-cta">
|
||||
<div class="about-flower-divider" aria-hidden="true">
|
||||
<img [src]="resolveImageUrl(config().logo_url)" alt="">
|
||||
<img [src]="resolveImageUrl(config().logo_url)" alt="" aria-hidden="true">
|
||||
</div>
|
||||
<h3>Become a Member</h3>
|
||||
<p class="section-intro">{{ config().about_donation_text }}</p>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="container">
|
||||
<div class="contact-header">
|
||||
<img src="svg/small-flower.svg" alt="" class="contact-flower" aria-hidden="true">
|
||||
<h2>Get in <span class="text-accent">Touch</span></h2>
|
||||
<h1>Get in <span class="text-accent">Touch</span></h1>
|
||||
<p class="section-intro">
|
||||
Have a song request, want to volunteer, or just want to say hello?
|
||||
We'd love to hear from you.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="container">
|
||||
<div class="events-header">
|
||||
<img src="svg/small-flower.svg" alt="" class="events-flower" aria-hidden="true">
|
||||
<h2>Upcoming <span class="text-accent">Events</span></h2>
|
||||
<h1>Upcoming <span class="text-accent">Events</span></h1>
|
||||
<p class="section-intro">{{ config().events_intro }}</p>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
@if (event.rsvp_url) {
|
||||
<a [href]="event.rsvp_url" class="event-rsvp" target="_blank" rel="noopener">RSVP →</a>
|
||||
} @else {
|
||||
<a href="#" class="event-rsvp">Learn More →</a>
|
||||
<a routerLink="/contact" [queryParams]="{subject: 'general'}" class="event-rsvp">Learn More →</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,18 +35,26 @@
|
||||
@if (config().donation_url) {
|
||||
<li><a [href]="config().donation_url" target="_blank" rel="noopener noreferrer">Become a Member</a></li>
|
||||
}
|
||||
<li><a href="#">Volunteer</a></li>
|
||||
<li><a href="#">Corporate Giving</a></li>
|
||||
<li><a href="#">Planned Giving</a></li>
|
||||
<li><a routerLink="/contact" [queryParams]="{subject: 'volunteer'}">Volunteer</a></li>
|
||||
<li><a routerLink="/contact" [queryParams]="{subject: 'advertising'}">Corporate Giving</a></li>
|
||||
<li><a routerLink="/contact" [queryParams]="{subject: 'general'}">Planned Giving</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Follow Us</h4>
|
||||
<div class="social-links">
|
||||
<a href="#" aria-label="Facebook" class="social-link">📘</a>
|
||||
<a href="#" aria-label="Twitter" class="social-link">🐦</a>
|
||||
<a href="#" aria-label="Instagram" class="social-link">📷</a>
|
||||
<a href="#" aria-label="YouTube" class="social-link">📺</a>
|
||||
@if (config().social_facebook) {
|
||||
<a [href]="config().social_facebook" target="_blank" rel="noopener noreferrer" aria-label="Facebook" class="social-link">📘</a>
|
||||
}
|
||||
@if (config().social_twitter) {
|
||||
<a [href]="config().social_twitter" target="_blank" rel="noopener noreferrer" aria-label="Twitter" class="social-link">🐦</a>
|
||||
}
|
||||
@if (config().social_instagram) {
|
||||
<a [href]="config().social_instagram" target="_blank" rel="noopener noreferrer" aria-label="Instagram" class="social-link">📷</a>
|
||||
}
|
||||
@if (config().social_youtube) {
|
||||
<a [href]="config().social_youtube" target="_blank" rel="noopener noreferrer" aria-label="YouTube" class="social-link">📺</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,11 @@ export interface StationConfig {
|
||||
play_store_icon_url: string;
|
||||
play_store_url: string;
|
||||
app_store_embed_html: string;
|
||||
// Social media
|
||||
social_facebook: string;
|
||||
social_twitter: string;
|
||||
social_instagram: string;
|
||||
social_youtube: string;
|
||||
// Page content
|
||||
hero_subtitle: string;
|
||||
about_intro: string;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="container">
|
||||
<div class="schedule-header">
|
||||
<img [src]="resolveImageUrl(config().logo_url)" alt="" class="schedule-flower" aria-hidden="true">
|
||||
<h2>Program <span class="text-accent">Schedule</span></h2>
|
||||
<h1>Program <span class="text-accent">Schedule</span></h1>
|
||||
<p class="section-intro">{{ config().schedule_intro }}</p>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user