Skip to content

Instantly share code, notes, and snippets.

@maietta
Created December 30, 2024 05:51
Show Gist options
  • Select an option

  • Save maietta/87f18e4290259c5c50ded0bd6442f2f3 to your computer and use it in GitHub Desktop.

Select an option

Save maietta/87f18e4290259c5c50ded0bd6442f2f3 to your computer and use it in GitHub Desktop.
Svelte 5 reactive grid/list layout.
<script lang="ts">
import { preferences } from '$lib/stores/preferences'; // Reactive store
import Pagination from './pagination.svelte';
import { truncateDescription, glance } from '$lib/realty/presentation';
let { data } = $props();
let selectedIndex = $state(1);
let listings = $derived(data.results.records);
let pagination = $derived(data.results.pagination);
$effect(() => {
const params = new URLSearchParams(window.location.search);
selectedIndex = Number(params.get('page')) || 1;
});
function getListedBy(record: any): {
agents: { role: string; name: string; office: string }[];
} {
const {
LA1AgentFirstName,
LA1AgentLastName,
LO1OfficeName,
LA2AgentFirstName,
LA2AgentLastName,
LO2OfficeName
} = record.data;
const agents = [
LA1AgentFirstName &&
LA1AgentLastName &&
LO1OfficeName && {
role: 'Listed by',
name: `${LA1AgentFirstName} ${LA1AgentLastName}`,
office: LO1OfficeName
},
LA2AgentFirstName &&
LO2OfficeName && {
role: 'Co-Listed by',
name: `${LA2AgentFirstName} ${LA2AgentLastName || ''}`.trim(),
office: LO2OfficeName
}
].filter(Boolean) as { role: string; name: string; office: string }[];
console.log(agents);
return { agents };
}
const layout = $derived($preferences.layout);
</script>
<!--
<svelte:head>
<title>{children?.()?.props?.title}</title>
</svelte:head> -->
<!-- Listing Info Layout -->
{#snippet listingInfo(listing: { data: { Class: any; Type: any } })}
<ol class="flex grow flex-col">
<li class="text-right text-sm italic">
{listing.data.Class} ({listing.data.Type})
</li>
{#each glance(listing) as [key, value]}
<li class="flex justify-between">
<strong>{key}:</strong>
<span>{value}</span>
</li>
{/each}
</ol>
{/snippet}
<div class="relative">
{#if listings && listings.length > 0}
{#if pagination.totalPages > 1}
<div class="sticky top-16 bg-[#f5f5f5] py-2">
<Pagination {pagination} />
</div>
{/if}
<div
class={`${
layout === 'grid'
? 'grid grid-cols-1 gap-4 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3'
: 'flex flex-col'
}`}
>
{#each listings as listing}
{@const listedBy = getListedBy(listing)}
<div
class={`${
layout === 'grid'
? 'block rounded-lg border-2 border-gray-200 hover:bg-white'
: 'mb-4 flex rounded-lg border-2 border-gray-200 hover:bg-white'
}`}
>
<!-- Image -->
<div
class={`${
layout === 'grid' ? 'overflow-hidden rounded-t-lg' : 'flex rounded-2xl px-2 pt-2'
}`}
>
<a href={listing.link}>
<img
src={listing.thumbnail}
alt="Thumbnail"
class={`${
layout === 'grid'
? 'h-48 w-full object-cover'
: 'rounded-lg rounded-bl-lg border-2 object-scale-down p-1 shadow-md'
}`}
/>
</a>
</div>
<!-- Listing Info -->
<div class={`${layout === 'grid' ? 'p-4' : 'flex w-full flex-col'}`}>
{#if layout === 'list'}
<div class="flex flex-1">
<div class="w-full py-2">
<div class="float-right min-w-[250px] rounded-bl-lg border-gray-200 px-4 pb-2">
{@render listingInfo(listing)}
</div>
<div class="flex-1 px-2">
{truncateDescription(listing.data.PublicRemarks, 60)}
</div>
</div>
</div>
{:else}
<div class="flex flex-1 flex-col">
{@render listingInfo(listing)}
</div>
{/if}
<!-- Listed By -->
<div
class={`${
layout === 'grid'
? 'px-4 pb-4'
: 'mt-4 mb-2 flex items-center justify-center rounded-lg px-4'
}`}
>
<div
class={`${layout === 'grid' ? 'text-sm text-gray-600' : 'flex flex-1 flex-col'}`}
>
{#each listedBy.agents as agent}
<p>
{agent.role}
{agent.name} of {agent.office}
</p>
{/each}
</div>
{#if layout === 'list'}
<div class="flex justify-end">
<a
href={listing.link}
class="w-full rounded-lg bg-black px-4 py-2 text-white sm:w-auto"
>
See Details
</a>
</div>
{/if}
</div>
</div>
</div>
{/each}
</div>
<Pagination {pagination} />
{:else}
<p>No listings found.</p>
{/if}
</div>
import { persisted } from 'svelte-persisted-store' // Cool library, but I do have my own I'm working on.
const defaults = {
layout: 'list' as 'list' | 'grid',
sort: 'price' as 'price' | 'date',
order: 'asc' as 'asc' | 'desc'
}
export const preferences = persisted('preferences', defaults);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment