SEO/AEO, Farb schema, breadcrumbs
This commit is contained in:
120
bizmatch/src/app/services/alt-text.service.ts
Normal file
120
bizmatch/src/app/services/alt-text.service.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { SelectOptionsService } from './select-options.service';
|
||||
|
||||
/**
|
||||
* Service for generating SEO-optimized alt text for images
|
||||
* Ensures consistent, keyword-rich alt text across the application
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AltTextService {
|
||||
private selectOptions = inject(SelectOptionsService);
|
||||
|
||||
/**
|
||||
* Generate alt text for business listing images
|
||||
* Format: "Business Name - Business Type for sale in City, State"
|
||||
* Example: "Italian Restaurant - Restaurant for sale in Austin, TX"
|
||||
*/
|
||||
generateBusinessListingAlt(listing: any): string {
|
||||
const location = this.getLocationString(listing.location);
|
||||
const businessType = listing.type ? this.selectOptions.getBusiness(listing.type) : 'Business';
|
||||
|
||||
return `${listing.title} - ${businessType} for sale in ${location}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for commercial property listing images
|
||||
* Format: "Property Type for sale - Title in City, State"
|
||||
* Example: "Retail Space for sale - Downtown storefront in Miami, FL"
|
||||
*/
|
||||
generatePropertyListingAlt(listing: any): string {
|
||||
const location = this.getLocationString(listing.location);
|
||||
const propertyType = listing.type ? this.selectOptions.getCommercialProperty(listing.type) : 'Commercial Property';
|
||||
|
||||
return `${propertyType} for sale - ${listing.title} in ${location}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for broker/user profile photos
|
||||
* Format: "First Last - Customer Type broker profile photo"
|
||||
* Example: "John Smith - Business broker profile photo"
|
||||
*/
|
||||
generateBrokerProfileAlt(user: any): string {
|
||||
const name = `${user.firstname || ''} ${user.lastname || ''}`.trim() || 'Broker';
|
||||
const customerType = user.customerSubType ? this.selectOptions.getCustomerSubType(user.customerSubType) : 'Business';
|
||||
|
||||
return `${name} - ${customerType} broker profile photo`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for company logos
|
||||
* Format: "Company Name company logo" or "Owner Name company logo"
|
||||
* Example: "ABC Realty company logo"
|
||||
*/
|
||||
generateCompanyLogoAlt(companyName?: string, ownerName?: string): string {
|
||||
const name = companyName || ownerName || 'Company';
|
||||
return `${name} company logo`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for listing card logo images
|
||||
* Includes business name and location for context
|
||||
*/
|
||||
generateListingCardLogoAlt(listing: any): string {
|
||||
const location = this.getLocationString(listing.location);
|
||||
return `${listing.title} - Business for sale in ${location}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for property images in detail view
|
||||
* Format: "Title - Property Type image (index)"
|
||||
* Example: "Downtown Office Space - Office building image 1 of 5"
|
||||
*/
|
||||
generatePropertyImageAlt(title: string, propertyType: string, imageIndex?: number, totalImages?: number): string {
|
||||
let alt = `${title} - ${propertyType}`;
|
||||
|
||||
if (imageIndex !== undefined && totalImages !== undefined && totalImages > 1) {
|
||||
alt += ` image ${imageIndex + 1} of ${totalImages}`;
|
||||
} else {
|
||||
alt += ' image';
|
||||
}
|
||||
|
||||
return alt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate alt text for business images in detail view
|
||||
* Format: "Title - Business Type image (index)"
|
||||
*/
|
||||
generateBusinessImageAlt(title: string, businessType: string, imageIndex?: number, totalImages?: number): string {
|
||||
let alt = `${title} - ${businessType}`;
|
||||
|
||||
if (imageIndex !== undefined && totalImages !== undefined && totalImages > 1) {
|
||||
alt += ` image ${imageIndex + 1} of ${totalImages}`;
|
||||
} else {
|
||||
alt += ' image';
|
||||
}
|
||||
|
||||
return alt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Get location string from location object
|
||||
* Returns: "City, STATE" or "County, STATE" or "STATE"
|
||||
*/
|
||||
private getLocationString(location: any): string {
|
||||
if (!location) return 'United States';
|
||||
|
||||
const city = location.name || location.county;
|
||||
const state = location.state || '';
|
||||
|
||||
if (city && state) {
|
||||
return `${city}, ${state}`;
|
||||
} else if (state) {
|
||||
return this.selectOptions.getState(state) || state;
|
||||
}
|
||||
|
||||
return 'United States';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user