SEO/AEO, Farb schema, breadcrumbs

This commit is contained in:
2025-11-29 23:41:54 +01:00
parent 4fa24c8f3d
commit d2953fd0d9
87 changed files with 5672 additions and 579 deletions

View File

@@ -7,11 +7,75 @@
<!-- Main Content -->
<div class="w-full p-4">
<div class="container mx-auto">
@if(listings?.length > 0) {
<!-- Breadcrumbs -->
<div class="mb-4">
<app-breadcrumbs [breadcrumbs]="breadcrumbs"></app-breadcrumbs>
</div>
<!-- SEO-optimized heading -->
<div class="mb-6">
<h1 class="text-3xl md:text-4xl font-bold text-neutral-900 mb-2">Businesses for Sale</h1>
<p class="text-lg text-neutral-600">Discover profitable business opportunities across the United States. Browse verified listings from business owners and brokers.</p>
</div>
<!-- Loading Skeleton -->
@if(isLoading) {
<h2 class="text-2xl font-semibold text-neutral-800 mb-4">Loading Business Listings...</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
@for (item of [1,2,3,4,5,6]; track item) {
<div class="bg-white rounded-lg drop-shadow-custom-bg-mobile md:drop-shadow-custom-bg overflow-hidden">
<div class="p-6 animate-pulse">
<!-- Category icon and text -->
<div class="flex items-center mb-4">
<div class="w-5 h-5 bg-neutral-200 rounded mr-2"></div>
<div class="h-5 bg-neutral-200 rounded w-32"></div>
</div>
<!-- Title -->
<div class="h-7 bg-neutral-200 rounded w-3/4 mb-4"></div>
<!-- Badges -->
<div class="flex justify-between mb-4">
<div class="h-6 bg-neutral-200 rounded-full w-20"></div>
<div class="h-6 bg-neutral-200 rounded-full w-16"></div>
</div>
<!-- Details -->
<div class="space-y-2 mb-4">
<div class="h-4 bg-neutral-200 rounded w-full"></div>
<div class="h-4 bg-neutral-200 rounded w-5/6"></div>
<div class="h-4 bg-neutral-200 rounded w-4/6"></div>
<div class="h-4 bg-neutral-200 rounded w-3/4"></div>
<div class="h-4 bg-neutral-200 rounded w-2/3"></div>
</div>
<!-- Button -->
<div class="h-12 bg-neutral-200 rounded-full w-full mt-4"></div>
</div>
</div>
}
</div>
} @else if(listings?.length > 0) {
<h2 class="text-2xl font-semibold text-neutral-800 mb-4">Available Business Listings</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
@for (listing of listings; track listing.id) {
<div class="bg-white rounded-lg drop-shadow-custom-bg-mobile md:drop-shadow-custom-bg overflow-hidden hover:shadow-xl">
<div class="bg-white rounded-lg drop-shadow-custom-bg-mobile md:drop-shadow-custom-bg overflow-hidden hover:shadow-2xl transition-all duration-300 hover:scale-[1.02] group">
<div class="p-6 flex flex-col h-full relative z-[0]">
<!-- Quick Actions Overlay -->
<div class="absolute top-4 right-4 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-20">
@if(user) {
<button
class="bg-white rounded-full p-2 shadow-lg transition-colors"
[class.bg-red-50]="isFavorite(listing)"
[title]="isFavorite(listing) ? 'Remove from favorites' : 'Save to favorites'"
(click)="toggleFavorite($event, listing)">
<i [class]="isFavorite(listing) ? 'fas fa-heart text-red-500' : 'far fa-heart text-red-500 hover:scale-110 transition-transform'"></i>
</button>
}
<button
class="bg-white rounded-full p-2 shadow-lg hover:bg-blue-50 transition-colors"
title="Share listing"
(click)="$event.stopPropagation()">
<i class="fas fa-share-alt text-blue-500 hover:scale-110 transition-transform"></i>
</button>
</div>
<div class="flex items-center mb-4">
<i [class]="selectOptions.getIconAndTextColorType(listing.type)" class="mr-2 text-xl"></i>
<span [class]="selectOptions.getTextColorType(listing.type)" class="font-bold text-lg">{{ selectOptions.getBusiness(listing.type) }}</span>
@@ -19,20 +83,20 @@
<h2 class="text-xl font-semibold mb-4">
{{ listing.title }}
@if(listing.draft) {
<span class="bg-red-100 text-red-800 text-sm font-medium me-2 ml-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">Draft</span>
<span class="bg-amber-100 text-amber-800 border border-amber-300 text-sm font-medium me-2 ml-2 px-2.5 py-0.5 rounded">Draft</span>
}
</h2>
<div class="flex justify-between">
<span class="w-fit inline-flex items-center justify-center px-2 py-1 mb-4 text-xs font-bold leading-none bg-gray-200 text-gray-700 rounded-full">
<span class="w-fit inline-flex items-center justify-center px-2 py-1 mb-4 text-xs font-bold leading-none bg-neutral-200 text-neutral-700 rounded-full">
{{ selectOptions.getState(listing.location.state) }}
</span>
@if (getListingBadge(listing); as badge) {
<span
class="mb-4 h-fit inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none rounded-full"
class="mb-4 h-fit inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none rounded-full border"
[ngClass]="{
'bg-emerald-100 text-emerald-800': badge === 'NEW',
'bg-blue-100 text-blue-800': badge === 'UPDATED'
'bg-emerald-100 text-emerald-800 border-emerald-300': badge === 'NEW',
'bg-teal-100 text-teal-800 border-teal-300': badge === 'UPDATED'
}"
>
{{ badge }}
@@ -40,40 +104,46 @@
}
</div>
<p class="text-base font-bold text-gray-800 mb-2">
<p class="text-base font-bold text-neutral-800 mb-2">
<strong>Asking price:</strong>
<span class="text-green-600">
<span class="text-success-600">
{{ listing?.price != null ? (listing.price | currency : 'USD' : 'symbol' : '1.0-0') : 'undisclosed' }}
</span>
</p>
<p class="text-sm text-gray-600 mb-2">
<p class="text-sm text-neutral-600 mb-2">
<strong>Sales revenue:</strong>
{{ listing?.salesRevenue != null ? (listing.salesRevenue | currency : 'USD' : 'symbol' : '1.0-0') : 'undisclosed' }}
</p>
<p class="text-sm text-gray-600 mb-2">
<p class="text-sm text-neutral-600 mb-2">
<strong>Net profit:</strong>
{{ listing?.cashFlow != null ? (listing.cashFlow | currency : 'USD' : 'symbol' : '1.0-0') : 'undisclosed' }}
</p>
<p class="text-sm text-gray-600 mb-2">
<p class="text-sm text-neutral-600 mb-2">
<strong>Location:</strong> {{ listing.location.name ? listing.location.name : listing.location.county ? listing.location.county : this.selectOptions.getState(listing.location.state) }}
</p>
<p class="text-sm text-gray-600 mb-4"><strong>Years established:</strong> {{ listing.established }}</p>
<img src="{{ env.imageBaseUrl }}/pictures/logo/{{ listing.imageName }}.avif?_ts={{ ts }}" alt="Company logo" class="absolute bottom-[80px] right-[20px] h-[45px] w-auto" />
<p class="text-sm text-neutral-600 mb-4"><strong>Years established:</strong> {{ listing.established }}</p>
@if(listing.imageName) {
<img [appLazyLoad]="env.imageBaseUrl + '/pictures/logo/' + listing.imageName + '.avif?_ts=' + ts"
[alt]="altText.generateListingCardLogoAlt(listing)"
class="absolute bottom-[80px] right-[20px] h-[45px] w-auto"
width="100"
height="45" />
}
<div class="flex-grow"></div>
<button
class="bg-green-500 text-white px-5 py-3 rounded-full w-full flex items-center justify-center mt-4 transition-colors duration-200 hover:bg-green-600"
[routerLink]="['/details-business-listing', listing.id]"
class="bg-success-600 text-white px-5 py-3 rounded-full w-full flex items-center justify-center mt-4 transition-all duration-200 hover:bg-success-700 hover:shadow-lg group/btn"
[routerLink]="['/business', listing.slug || listing.id]"
>
View Full Listing
<i class="fas fa-arrow-right ml-2"></i>
<span class="font-semibold">View Opportunity</span>
<i class="fas fa-arrow-right ml-2 group-hover/btn:translate-x-1 transition-transform duration-200"></i>
</button>
</div>
</div>
}
</div>
} @else if (listings?.length === 0) {
<div class="w-full flex items-center flex-wrap justify-center gap-10">
<div class="grid gap-4 w-60">
<div class="w-full flex items-center flex-wrap justify-center gap-10 py-12">
<div class="grid gap-6 max-w-2xl w-full">
<svg class="mx-auto" xmlns="http://www.w3.org/2000/svg" width="154" height="161" viewBox="0 0 154 161" fill="none">
<path
d="M0.0616455 84.4268C0.0616455 42.0213 34.435 7.83765 76.6507 7.83765C118.803 7.83765 153.224 42.0055 153.224 84.4268C153.224 102.42 147.026 118.974 136.622 132.034C122.282 150.138 100.367 161 76.6507 161C52.7759 161 30.9882 150.059 16.6633 132.034C6.25961 118.974 0.0616455 102.42 0.0616455 84.4268Z"
@@ -114,11 +184,57 @@
<circle cx="61.6001" cy="31.0854" r="1.36752" fill="#4F46E5" />
<circle cx="67.0702" cy="31.0854" r="1.36752" fill="#4F46E5" />
</svg>
<div>
<h2 class="text-center text-black text-xl font-semibold leading-loose pb-2">Theres no listing here</h2>
<p class="text-center text-black text-base font-normal leading-relaxed pb-4">Try changing your filters to <br />see listings</p>
<div class="flex gap-3">
<button (click)="clearAllFilters()" class="w-full px-3 py-2 rounded-full border border-gray-300 text-gray-900 text-xs font-semibold leading-4">Clear Filter</button>
<div class="text-center">
<h2 class="text-black text-2xl font-semibold leading-loose pb-2">No listings found</h2>
<p class="text-neutral-600 text-base font-normal leading-relaxed pb-6">We couldn't find any businesses matching your criteria.<br />Try adjusting your filters or explore popular categories below.</p>
<!-- Action Buttons -->
<div class="flex flex-col sm:flex-row gap-3 justify-center mb-8">
<button (click)="clearAllFilters()" class="px-6 py-3 rounded-full bg-primary-600 text-white text-sm font-semibold hover:bg-primary-700 transition-colors">
<i class="fas fa-redo mr-2"></i>Clear All Filters
</button>
<button [routerLink]="['/home']" class="px-6 py-3 rounded-full border-2 border-neutral-300 text-neutral-700 text-sm font-semibold hover:border-primary-600 hover:text-primary-600 transition-colors">
<i class="fas fa-home mr-2"></i>Back to Home
</button>
</div>
<!-- Popular Categories Suggestions -->
<div class="mt-8 p-6 bg-neutral-50 rounded-lg">
<h3 class="text-lg font-semibold text-neutral-800 mb-4">
<i class="fas fa-fire text-orange-500 mr-2"></i>Popular Categories
</h3>
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
<button (click)="filterByCategory('foodAndRestaurant')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-utensils mr-2"></i>Restaurants
</button>
<button (click)="filterByCategory('retail')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-store mr-2"></i>Retail
</button>
<button (click)="filterByCategory('realEstate')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-building mr-2"></i>Real Estate
</button>
<button (click)="filterByCategory('service')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-cut mr-2"></i>Services
</button>
<button (click)="filterByCategory('franchise')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-handshake mr-2"></i>Franchise
</button>
<button (click)="filterByCategory('professional')" class="px-4 py-2 bg-white rounded-lg border border-neutral-200 hover:border-primary-500 hover:bg-primary-50 text-sm text-neutral-700 hover:text-primary-600 transition-all">
<i class="fas fa-briefcase mr-2"></i>Professional
</button>
</div>
</div>
<!-- Helpful Tips -->
<div class="mt-6 p-4 bg-primary-50 border border-primary-100 rounded-lg text-left">
<h4 class="font-semibold text-primary-900 mb-2 flex items-center">
<i class="fas fa-lightbulb mr-2"></i>Search Tips
</h4>
<ul class="text-sm text-primary-800 space-y-1">
<li>• Try expanding your search radius</li>
<li>• Consider adjusting your price range</li>
<li>• Browse all categories to discover opportunities</li>
</ul>
</div>
</div>
</div>
@@ -131,5 +247,5 @@
</div>
<!-- Filter Button for Mobile -->
<button (click)="openFilterModal()" class="md:hidden fixed bottom-4 right-4 bg-blue-500 text-white p-3 rounded-full shadow-lg z-20"><i class="fas fa-filter"></i> Filter</button>
<button (click)="openFilterModal()" class="md:hidden fixed bottom-4 right-4 bg-primary-500 text-white p-3 rounded-full shadow-lg z-20"><i class="fas fa-filter"></i> Filter</button>
</div>