~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
112 lines · 3.1 KB Raw History
<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query'
  import GalleryGrid from '$lib/components/organisms/GalleryGrid.svelte'
  import PageHeading from '$lib/components/molecules/PageHeading.svelte'
  import OGMeta from '$lib/components/atoms/OGMeta.svelte'
  import { camerasQuery, locationsQuery, recentFeedQuery } from '$lib/queries'

  // How many chips before deferring to the full index pages.
  const CHIP_LIMIT = 10

  const cameras = createQuery(() => camerasQuery())
  const locations = createQuery(() => locationsQuery())
  const feed = createQuery(() => recentFeedQuery())

  const cameraChips = $derived((cameras.data ?? []).slice(0, CHIP_LIMIT))
  const locationChips = $derived((locations.data ?? []).slice(0, CHIP_LIMIT))
  const items = $derived(feed.data?.items ?? [])
</script>

<OGMeta title="Explore - grain" description="Browse grain by camera and place." />

<div class="explore">
  <PageHeading title="Explore" />

  <section class="chip-group">
    <h2 class="chip-label">Cameras</h2>
    <div class="chips">
      {#each cameraChips as c (c.camera)}
        <a class="chip" href="/camera/{encodeURIComponent(c.camera)}">{c.camera}</a>
      {/each}
      {#if (cameras.data ?? []).length > CHIP_LIMIT}
        <a class="chip see-all" href="/cameras">See all →</a>
      {/if}
    </div>
  </section>

  <section class="chip-group">
    <h2 class="chip-label">Locations</h2>
    <div class="chips">
      {#each locationChips as loc (loc.name)}
        <a
          class="chip"
          href="/location/{encodeURIComponent(loc.h3Index)}?name={encodeURIComponent(loc.name)}"
        >
          {loc.name}
        </a>
      {/each}
      {#if (locations.data ?? []).length > CHIP_LIMIT}
        <a class="chip see-all" href="/locations">See all →</a>
      {/if}
    </div>
  </section>

  <GalleryGrid {items} loading={feed.isLoading} emptyText="Nothing to explore yet." />
</div>

<style>
  /* No horizontal padding here: the grid runs edge to edge, so the inset
     belongs to the text above it rather than to the page. Matches /location. */
  .explore {
    padding: 8px 0 32px;
  }
  .chip-group {
    padding-inline: 16px;
  }
  .chip-group {
    margin-top: 18px;
  }
  /* GalleryGrid owns its own markup, so reach in for the one bit of spacing
     that belongs to this page's rhythm rather than to the grid. */
  .explore :global(.grid) {
    margin-top: 24px;
  }
  .chip-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin: 0 0 8px;
  }
  .chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }
  .chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 14px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-decoration: none;
    background: var(--bg-surface);
    transition: color 0.12s, background 0.12s;
  }
  .chip:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
  }
  .see-all {
    color: var(--grain);
    background: none;
  }
  .see-all:hover {
    color: var(--grain);
    background: var(--grain-glow);
  }
</style>