Step 2.4: Build Property card component with price, specs, status badge
This commit is contained in:
@@ -407,4 +407,4 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2025-11-28 16:33:30
|
-- Dump completed on 2025-11-28 16:34:33
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -14,6 +14,7 @@
|
|||||||
@import '../template-parts/content/content-card.scss';
|
@import '../template-parts/content/content-card.scss';
|
||||||
@import '../template-parts/content/content-single.scss';
|
@import '../template-parts/content/content-single.scss';
|
||||||
@import '../template-parts/content/content-404.scss';
|
@import '../template-parts/content/content-404.scss';
|
||||||
|
@import '../template-parts/property/property-card.scss';
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// CSS Custom Properties (Design Tokens)
|
// CSS Custom Properties (Design Tokens)
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Property Card Template Part
|
||||||
|
*
|
||||||
|
* Displays a property in card format for archive views
|
||||||
|
*
|
||||||
|
* @package HomeProz
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Prevent direct access
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get property data
|
||||||
|
$property_id = get_the_ID();
|
||||||
|
$price = get_field('property_price', $property_id);
|
||||||
|
$street_address = get_field('street_address', $property_id);
|
||||||
|
$city = get_field('city', $property_id);
|
||||||
|
$state = get_field('state', $property_id);
|
||||||
|
$bedrooms = get_field('bedrooms', $property_id);
|
||||||
|
$bathrooms = get_field('bathrooms', $property_id);
|
||||||
|
$square_feet = get_field('square_feet', $property_id);
|
||||||
|
$short_description = get_field('short_description', $property_id);
|
||||||
|
|
||||||
|
// Get status from taxonomy
|
||||||
|
$status_terms = get_the_terms($property_id, 'property_status');
|
||||||
|
$status = $status_terms && !is_wp_error($status_terms) ? $status_terms[0]->name : 'Active';
|
||||||
|
$status_class = homeproz_get_status_class($status);
|
||||||
|
|
||||||
|
// Format address
|
||||||
|
$full_address = $street_address;
|
||||||
|
if ($city) {
|
||||||
|
$full_address .= ', ' . $city;
|
||||||
|
}
|
||||||
|
if ($state) {
|
||||||
|
$full_address .= ', ' . $state;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<article id="property-<?php echo esc_attr($property_id); ?>" <?php post_class('property-card card'); ?>>
|
||||||
|
<a href="<?php the_permalink(); ?>" class="property-card-image">
|
||||||
|
<?php if (has_post_thumbnail()) : ?>
|
||||||
|
<?php the_post_thumbnail('property-card', array('loading' => 'lazy')); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="property-card-placeholder">
|
||||||
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
|
||||||
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||||
|
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($status) : ?>
|
||||||
|
<span class="property-card-badge badge <?php echo esc_attr($status_class); ?>">
|
||||||
|
<?php echo esc_html($status); ?>
|
||||||
|
</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="property-card-content">
|
||||||
|
<div class="property-card-price">
|
||||||
|
<?php echo esc_html(homeproz_format_price($price)); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="property-card-title">
|
||||||
|
<a href="<?php the_permalink(); ?>">
|
||||||
|
<?php echo esc_html($full_address ?: get_the_title()); ?>
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<?php if ($bedrooms || $bathrooms || $square_feet) : ?>
|
||||||
|
<ul class="property-card-specs">
|
||||||
|
<?php if ($bedrooms) : ?>
|
||||||
|
<li class="spec-item">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<path d="M3 7v11h18V7M3 7V4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v3M3 7h18M7 11h4v4H7zM14 11h3"/>
|
||||||
|
</svg>
|
||||||
|
<span><?php echo esc_html($bedrooms); ?> <?php echo $bedrooms == 1 ? 'Bed' : 'Beds'; ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($bathrooms) : ?>
|
||||||
|
<li class="spec-item">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<path d="M4 12h16M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7M4 12V6a2 2 0 0 1 2-2h3v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V4"/>
|
||||||
|
</svg>
|
||||||
|
<span><?php echo esc_html($bathrooms); ?> <?php echo $bathrooms == 1 ? 'Bath' : 'Baths'; ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($square_feet) : ?>
|
||||||
|
<li class="spec-item">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
||||||
|
<path d="M3 9h18M9 3v18"/>
|
||||||
|
</svg>
|
||||||
|
<span><?php echo esc_html(number_format($square_feet)); ?> sqft</span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($short_description) : ?>
|
||||||
|
<p class="property-card-excerpt">
|
||||||
|
<?php echo esc_html(wp_trim_words($short_description, 15, '...')); ?>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<a href="<?php the_permalink(); ?>" class="property-card-link">
|
||||||
|
View Details
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
||||||
|
<path d="M5 12h14M12 5l7 7-7 7"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* Property Card Styles
|
||||||
|
*
|
||||||
|
* @package HomeProz
|
||||||
|
*/
|
||||||
|
|
||||||
|
.property-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-image {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
aspect-ratio: 16 / 10;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--color-bg-dark);
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: var(--color-bg-dark);
|
||||||
|
color: var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.75rem;
|
||||||
|
left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-price {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-title {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-accent-light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property specs (beds, baths, sqft)
|
||||||
|
.property-card-specs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 0 0.75rem 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spec-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
color: var(--color-accent);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-excerpt {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-sold);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-card-link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-accent-light);
|
||||||
|
text-decoration: none;
|
||||||
|
margin-top: auto;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property grid layout
|
||||||
|
.properties-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Results count and meta
|
||||||
|
.properties-meta {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.properties-count {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No results message
|
||||||
|
.no-properties {
|
||||||
|
text-align: center;
|
||||||
|
padding: 4rem 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user