Implement oc2 listing improvements

This commit is contained in:
fatihalp 2026-03-07 20:21:11 +03:00
parent b1293d3960
commit dbe1dc97ce
2 changed files with 274 additions and 40 deletions

View File

@ -59,6 +59,7 @@
$reportEmail = config('mail.from.address', 'support@example.com'); $reportEmail = config('mail.from.address', 'support@example.com');
$reportUrl = 'mailto:'.$reportEmail.'?subject='.rawurlencode('Report listing #'.$listing->getKey()); $reportUrl = 'mailto:'.$reportEmail.'?subject='.rawurlencode('Report listing #'.$listing->getKey());
$shareUrl = route('listings.show', $listing);
$overviewItems = collect([ $overviewItems = collect([
['label' => 'Listing ID', 'value' => '#'.$listing->getKey()], ['label' => 'Listing ID', 'value' => '#'.$listing->getKey()],
@ -108,26 +109,41 @@
@endif @endif
</div> </div>
@auth <div class="lt-gallery-utility">
<form method="POST" action="{{ route('favorites.listings.toggle', $listing) }}"> <button
@csrf type="button"
<button class="lt-icon-btn"
type="submit" data-listing-share
class="lt-icon-btn {{ $isListingFavorited ? 'is-active' : '' }}" data-share-url="{{ $shareUrl }}"
aria-label="{{ $isListingFavorited ? 'Remove from saved listings' : 'Save listing' }}" data-share-title="{{ $displayTitle }}"
> aria-label="Share listing"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9">
<path d="M15 8a3 3 0 1 0-2.83-4H12a3 3 0 0 0 .17 1L8.91 6.94a3 3 0 0 0-1.91-.69 3 3 0 1 0 1.91 5.31l3.27 1.94A3 3 0 0 0 12 15a3 3 0 1 0 2.82 4H15a3 3 0 0 0-.17-1l-3.26-1.94a3 3 0 0 0 0-3.12L14.83 10A3 3 0 0 0 15 10h0a3 3 0 0 0 0-2Z"/>
</svg>
</button>
@auth
<form method="POST" action="{{ route('favorites.listings.toggle', $listing) }}">
@csrf
<button
type="submit"
class="lt-icon-btn {{ $isListingFavorited ? 'is-active' : '' }}"
aria-label="{{ $isListingFavorited ? 'Remove from saved listings' : 'Save listing' }}"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9">
<path d="M12 21l-1.45-1.32C5.4 15.03 2 12.01 2 8.31 2 5.3 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.08A6.04 6.04 0 0116.5 3C19.58 3 22 5.3 22 8.31c0 3.7-3.4 6.72-8.55 11.39L12 21z"/>
</svg>
</button>
</form>
@else
<a href="{{ route('login') }}" class="lt-icon-btn" aria-label="Sign in to save this listing">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9">
<path d="M12 21l-1.45-1.32C5.4 15.03 2 12.01 2 8.31 2 5.3 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.08A6.04 6.04 0 0116.5 3C19.58 3 22 5.3 22 8.31c0 3.7-3.4 6.72-8.55 11.39L12 21z"/> <path d="M12 21l-1.45-1.32C5.4 15.03 2 12.01 2 8.31 2 5.3 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.08A6.04 6.04 0 0116.5 3C19.58 3 22 5.3 22 8.31c0 3.7-3.4 6.72-8.55 11.39L12 21z"/>
</svg> </svg>
</button> </a>
</form> @endauth
@else </div>
<a href="{{ route('login') }}" class="lt-icon-btn" aria-label="Sign in to save this listing">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9">
<path d="M12 21l-1.45-1.32C5.4 15.03 2 12.01 2 8.31 2 5.3 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.08A6.04 6.04 0 0116.5 3C19.58 3 22 5.3 22 8.31c0 3.7-3.4 6.72-8.55 11.39L12 21z"/>
</svg>
</a>
@endauth
</div> </div>
@if($initialGalleryImage) @if($initialGalleryImage)
@ -171,13 +187,13 @@
<section class="lt-card lt-summary-card"> <section class="lt-card lt-summary-card">
<div class="lt-summary-copy"> <div class="lt-summary-copy">
<p class="lt-overline">{{ $listing->category?->name ?? 'Marketplace listing' }}</p> <p class="lt-overline">{{ $listing->category?->name ?? 'Marketplace listing' }}</p>
<h1 class="lt-title">{{ $displayTitle }}</h1>
<div class="lt-price">{{ $priceLabel }}</div> <div class="lt-price">{{ $priceLabel }}</div>
<p class="lt-subtitle"> <h1 class="lt-title">{{ $displayTitle }}</h1>
<span>{{ $locationLabel !== '' ? $locationLabel : 'Location not specified' }}</span> <div class="lt-summary-meta-row">
<span aria-hidden="true">·</span> <span class="lt-summary-meta-item">{{ $locationLabel !== '' ? $locationLabel : 'Location not specified' }}</span>
<span>{{ $postedAgo }}</span> <span class="lt-summary-meta-item">{{ $publishedAt }}</span>
</p> </div>
<p class="lt-subtitle">{{ $postedAgo }}</p>
</div> </div>
<div class="lt-overview-grid"> <div class="lt-overview-grid">
@ -348,6 +364,56 @@
</aside> </aside>
</div> </div>
<div class="lt-mobile-actions">
<div class="lt-mobile-actions-shell">
<div class="lt-mobile-actions-row">
@if(! $listing->user)
<button type="button" class="lt-btn" disabled>Unavailable</button>
@elseif($canContactSeller)
@if($existingConversationId)
<a href="{{ route('panel.inbox.index', ['conversation' => $existingConversationId]) }}" class="lt-btn">
Message
</a>
@else
<form method="POST" action="{{ route('conversations.start', $listing) }}" class="lt-action-form">
@csrf
<button type="submit" class="lt-btn">Message</button>
</form>
@endif
@elseif($isOwnListing)
<button type="button" class="lt-btn" disabled>Your listing</button>
@else
<a href="{{ route('login') }}" class="lt-btn">Message</a>
@endif
@if($primaryContactHref)
<a href="{{ $primaryContactHref }}" class="lt-btn lt-btn-outline">{{ $primaryContactLabel }}</a>
@else
<button type="button" class="lt-btn lt-btn-outline" disabled>No contact</button>
@endif
</div>
@if(! $listing->user)
<button type="button" class="lt-btn lt-btn-main" disabled>Unavailable</button>
@elseif($canContactSeller)
@if($existingConversationId)
<a href="{{ route('panel.inbox.index', ['conversation' => $existingConversationId]) }}" class="lt-btn lt-btn-main">
Make offer
</a>
@else
<form method="POST" action="{{ route('conversations.start', $listing) }}" class="lt-action-form">
@csrf
<button type="submit" class="lt-btn lt-btn-main">Make offer</button>
</form>
@endif
@elseif($isOwnListing)
<button type="button" class="lt-btn lt-btn-main" disabled>Manage listing</button>
@else
<a href="{{ route('login') }}" class="lt-btn lt-btn-main">Make offer</a>
@endif
</div>
</div>
@if(($relatedListings ?? collect())->isNotEmpty() || ($themePillCategories ?? collect())->isNotEmpty()) @if(($relatedListings ?? collect())->isNotEmpty() || ($themePillCategories ?? collect())->isNotEmpty())
<section class="lt-related"> <section class="lt-related">
@if(($relatedListings ?? collect())->isNotEmpty()) @if(($relatedListings ?? collect())->isNotEmpty())
@ -485,6 +551,32 @@
track.scrollBy({ left: amount(), behavior: 'smooth' }); track.scrollBy({ left: amount(), behavior: 'smooth' });
}); });
}); });
document.querySelectorAll('[data-listing-share]').forEach((button) => {
button.addEventListener('click', async () => {
const url = button.dataset.shareUrl || window.location.href;
const title = button.dataset.shareTitle || document.title;
if (navigator.share) {
try {
await navigator.share({ title, url });
return;
} catch (error) {
if (error?.name === 'AbortError') {
return;
}
}
}
try {
await navigator.clipboard.writeText(url);
button.classList.add('is-active');
window.setTimeout(() => button.classList.remove('is-active'), 1200);
} catch (error) {
window.prompt('Copy this link', url);
}
});
});
})(); })();
</script> </script>
@endsection @endsection

View File

@ -849,6 +849,12 @@ summary::-webkit-details-marker {
gap: 8px; gap: 8px;
} }
.lt-gallery-utility {
display: flex;
align-items: center;
gap: 10px;
}
.lt-badge { .lt-badge {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -997,12 +1003,30 @@ summary::-webkit-details-marker {
} }
.lt-subtitle { .lt-subtitle {
display: flex; margin-top: 10px;
flex-wrap: wrap;
gap: 10px;
margin-top: 12px;
color: var(--oc-muted); color: var(--oc-muted);
font-size: 1rem; font-size: 0.92rem;
line-height: 1.5;
}
.lt-summary-meta-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
margin-top: 18px;
padding-top: 16px;
border-top: 1px solid rgba(29, 29, 31, 0.08);
}
.lt-summary-meta-item {
color: #4b5563;
font-size: 0.92rem;
line-height: 1.5;
}
.lt-summary-meta-item:last-child {
text-align: right;
} }
.lt-overview-grid { .lt-overview-grid {
@ -1294,6 +1318,10 @@ summary::-webkit-details-marker {
margin-top: 30px; margin-top: 30px;
} }
.lt-mobile-actions {
display: none;
}
.lt-related-head { .lt-related-head {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -1513,7 +1541,7 @@ summary::-webkit-details-marker {
@media (max-width: 720px) { @media (max-width: 720px) {
.lt-wrap { .lt-wrap {
padding: 18px 12px 40px; padding: 18px 12px calc(130px + env(safe-area-inset-bottom, 0px));
} }
.lt-card { .lt-card {
@ -1522,28 +1550,103 @@ summary::-webkit-details-marker {
.lt-media-card, .lt-media-card,
.lt-summary-card, .lt-summary-card,
.lt-detail-card, .lt-detail-card {
.lt-side-card {
padding: 14px; padding: 14px;
} }
.lt-media-card {
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
backdrop-filter: none;
}
.lt-gallery-main, .lt-gallery-main,
.lt-gallery-main img, .lt-gallery-main img,
.lt-gallery-main-empty { .lt-gallery-main-empty {
min-height: 360px; min-height: 420px;
}
.lt-gallery-main {
border-radius: 0;
background: #2b2d31;
box-shadow: none;
}
.lt-gallery-main::after {
display: none;
} }
.lt-gallery-main img { .lt-gallery-main img {
padding: 26px; padding: 0;
object-fit: contain;
} }
.lt-title { .lt-title {
max-width: none; max-width: none;
font-size: 2rem; font-size: 1.18rem;
line-height: 1.45;
letter-spacing: -0.02em;
} }
.lt-price { .lt-price {
font-size: 1.8rem; margin-top: 0;
font-size: 1.95rem;
}
.lt-overline,
.lt-overview-grid,
.lt-gallery-pills,
.lt-side-card,
.lt-contact-strip,
.lt-report,
.lt-policy {
display: none;
}
.lt-gallery-top {
align-items: flex-start;
}
.lt-gallery-utility {
margin-left: auto;
}
.lt-icon-btn,
.lt-gallery-nav {
border-color: rgba(255, 255, 255, 0.14);
background: rgba(29, 29, 31, 0.52);
color: #ffffff;
box-shadow: none;
backdrop-filter: blur(12px);
}
.lt-summary-card {
position: relative;
z-index: 3;
margin-top: -22px;
border-radius: 22px 22px 0 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
background: rgba(255, 255, 255, 0.98);
}
.lt-summary-card + .lt-detail-card {
margin-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
box-shadow: 0 18px 36px rgba(15, 23, 42, 0.06);
}
.lt-summary-meta-row {
margin-top: 14px;
padding-top: 14px;
}
.lt-summary-meta-item {
font-size: 0.84rem;
} }
.lt-overview-grid, .lt-overview-grid,
@ -1566,6 +1669,36 @@ summary::-webkit-details-marker {
.lt-rel-photo { .lt-rel-photo {
height: 156px; height: 156px;
} }
.lt-mobile-actions {
display: block;
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 45;
padding: 10px 10px calc(10px + env(safe-area-inset-bottom, 0px));
background: linear-gradient(180deg, rgba(245, 245, 247, 0) 0%, rgba(245, 245, 247, 0.88) 28%, rgba(245, 245, 247, 0.98) 100%);
backdrop-filter: blur(14px);
}
.lt-mobile-actions-shell {
display: grid;
gap: 10px;
max-width: 28rem;
margin: 0 auto;
padding: 10px;
border: 1px solid rgba(29, 29, 31, 0.08);
border-radius: 22px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12);
}
.lt-mobile-actions-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
@ -1581,11 +1714,7 @@ summary::-webkit-details-marker {
.lt-gallery-main, .lt-gallery-main,
.lt-gallery-main img, .lt-gallery-main img,
.lt-gallery-main-empty { .lt-gallery-main-empty {
min-height: 300px; min-height: 392px;
}
.lt-gallery-main img {
padding: 18px;
} }
.lt-gallery-top { .lt-gallery-top {
@ -1605,6 +1734,10 @@ summary::-webkit-details-marker {
padding: 16px; padding: 16px;
} }
.lt-summary-card {
margin-top: -18px;
}
.lt-seller-name { .lt-seller-name {
font-size: 1.35rem; font-size: 1.35rem;
} }
@ -1612,6 +1745,15 @@ summary::-webkit-details-marker {
.lt-contact-strip { .lt-contact-strip {
flex-direction: column; flex-direction: column;
} }
.lt-mobile-actions {
padding-inline: 4px;
}
.lt-mobile-actions-shell {
border-radius: 18px;
padding: 8px;
}
} }
html { html {