import { LitElement, html, css } from 'lit'; import { grainApi } from '../../services/grain-api.js'; import '../templates/grain-feed-layout.js'; import '../organisms/grain-gallery-card.js'; import '../molecules/grain-profile-card.js'; import '../atoms/grain-spinner.js'; import '../atoms/grain-input.js'; export class GrainExplore extends LitElement { static properties = { _query: { state: true }, _activeTab: { state: true }, _galleries: { state: true }, _profiles: { state: true }, _loading: { state: true }, _hasMore: { state: true }, _cursor: { state: true } }; static styles = css` :host { display: block; } .search-container { position: sticky; top: 0; background: var(--color-bg-primary); padding: var(--space-sm); z-index: 10; } .search-container::after { content: ''; display: block; max-width: var(--feed-max-width); margin: 0 auto; border-bottom: 1px solid var(--color-border); margin-top: var(--space-sm); } .search-container grain-input { max-width: var(--feed-max-width); margin: 0 auto; } .tabs { display: flex; max-width: var(--feed-max-width); margin: 0 auto; border-bottom: 1px solid var(--color-border); } .tab { flex: 1; padding: var(--space-sm) var(--space-md); background: none; border: none; color: var(--color-text-secondary); font-size: var(--font-size-sm); cursor: pointer; border-bottom: 2px solid transparent; } .tab.active { color: var(--color-text-primary); border-bottom-color: var(--color-text-primary); } .empty { padding: var(--space-xl); text-align: center; color: var(--color-text-secondary); } .profiles-list { max-width: var(--feed-max-width); margin: 0 auto; padding: var(--space-sm); } #sentinel { height: 1px; } `; #debounceTimer = null; #observer = null; constructor() { super(); this._query = ''; this._activeTab = 'galleries'; this._galleries = []; this._profiles = []; this._loading = false; this._hasMore = false; this._cursor = null; } disconnectedCallback() { super.disconnectedCallback(); this.#observer?.disconnect(); if (this.#debounceTimer) clearTimeout(this.#debounceTimer); } async firstUpdated() { this.#setupInfiniteScroll(); const input = this.shadowRoot.querySelector('grain-input'); await input?.updateComplete; input?.focus(); } #handleInput(e) { const value = e.detail?.value ?? e.target.value; this._query = value; if (this.#debounceTimer) clearTimeout(this.#debounceTimer); if (value.length < 2) { this._galleries = []; this._profiles = []; this._hasMore = false; return; } this.#debounceTimer = setTimeout(() => { this.#search(); }, 300); } #handleClear() { this._query = ''; this._galleries = []; this._profiles = []; this._hasMore = false; this._cursor = null; } #handleTabClick(tab) { if (this._activeTab === tab) return; this._activeTab = tab; this._cursor = null; this._hasMore = false; if (this._query.length >= 2) { this.#search(); } } async #search() { this._loading = true; this._cursor = null; try { if (this._activeTab === 'galleries') { const result = await grainApi.searchGalleries(this._query, { first: 10 }); this._galleries = result.galleries; this._hasMore = result.pageInfo.hasNextPage; this._cursor = result.pageInfo.endCursor; } else { const result = await grainApi.searchProfiles(this._query, { first: 20 }); this._profiles = result.profiles; this._hasMore = result.pageInfo.hasNextPage; this._cursor = result.pageInfo.endCursor; } } catch (err) { console.error('Search failed:', err); } finally { this._loading = false; } } async #loadMore() { if (this._loading || !this._hasMore || this._query.length < 2) return; this._loading = true; try { if (this._activeTab === 'galleries') { const result = await grainApi.searchGalleries(this._query, { first: 10, after: this._cursor }); this._galleries = [...this._galleries, ...result.galleries]; this._hasMore = result.pageInfo.hasNextPage; this._cursor = result.pageInfo.endCursor; } else { const result = await grainApi.searchProfiles(this._query, { first: 20, after: this._cursor }); this._profiles = [...this._profiles, ...result.profiles]; this._hasMore = result.pageInfo.hasNextPage; this._cursor = result.pageInfo.endCursor; } } catch (err) { console.error('Load more failed:', err); } finally { this._loading = false; } } #setupInfiniteScroll() { const sentinel = this.shadowRoot.getElementById('sentinel'); if (!sentinel) return; this.#observer = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { this.#loadMore(); } }, { rootMargin: '200px' } ); this.#observer.observe(sentinel); } #renderResults() { if (this._query.length < 2) { return html`
Search for galleries or users
`; } if (this._activeTab === 'galleries') { if (!this._loading && this._galleries.length === 0) { return html`No galleries found
`; } return html`No users found
`; } return html`