Something went wrong. Try again.
grain.social is a photo sharing platform built on atproto. grain.social
appview atproto photography
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192<script lang="ts"> import type { Snippet } from 'svelte'
let { onRefresh, children, }: { onRefresh: () => Promise<void> children: Snippet } = $props()
let refreshing = $state(false) let pullY = $state(0) let pulling = $state(false) let startY = 0
function onTouchStart(e: TouchEvent) { const scroller = document.querySelector('main.col-center') if (scroller && scroller.scrollTop === 0) { startY = e.touches[0].clientY pulling = true } }
function onTouchMove(e: TouchEvent) { if (!pulling) return const dy = e.touches[0].clientY - startY if (dy > 0) { pullY = Math.min(dy * 0.4, 80) } else { pullY = 0 } }
async function onTouchEnd() { if (!pulling) return pulling = false if (pullY >= 50) { refreshing = true pullY = 50 await onRefresh() refreshing = false } pullY = 0 }</script>
{#if pullY > 0 || refreshing} <div class="pull-pill" style:transform="translateY({pullY - 36}px)" style:opacity={Math.min(pullY / 40, 1)}> <svg class="pull-spinner" class:spinning={refreshing} width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> <path d="M21 12a9 9 0 1 1-6.219-8.56" /> </svg> </div>{/if}
<!-- svelte-ignore a11y_no_static_element_interactions --><div ontouchstart={onTouchStart} ontouchmove={onTouchMove} ontouchend={onTouchEnd}> {@render children()}</div>
<style> .pull-pill { position: fixed; top: 0; left: 50%; translate: -50% 0; z-index: 100; display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 50%; background: var(--bg-elevated); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); color: var(--text-secondary); pointer-events: none; transition: transform 0.2s ease, opacity 0.15s ease; } .pull-spinner.spinning { animation: spin 0.8s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }</style>