Initial commit: IndeeHub decentralized streaming platform
Built a complete Netflix-style streaming interface for IndeeHub's decentralized media platform with real film content. Features: - Vue 3 + TypeScript + Vite setup with hot module reloading - Netflix-inspired UI with hero section and horizontal scrolling content rows - Glass morphism design system with custom Tailwind configuration - 20+ real IndeeHub films organized into 6 categories (Bitcoin, Documentaries, Drama, etc.) - Full-featured video player component with custom controls - Mobile-responsive design with bottom navigation - Nostr integration ready (nostr-tools, relay pool, NIP-71 support) - Pinia state management for content - MCP tools configured (Filesystem, Memory, Nostr, Puppeteer) Components: - Browse.vue: Main streaming interface with hero and content rows - ContentRow.vue: Horizontal scrolling film cards with navigation arrows - VideoPlayer.vue: Custom video player with play/pause, seek, volume, fullscreen - MobileNav.vue: Bottom tab navigation for mobile devices Tech Stack: - Frontend: Vue 3 (Composition API), TypeScript - Build: Vite 7 - Styling: Tailwind CSS with custom theme - State: Pinia 3 - Router: Vue Router 4.6 - Protocol: Nostr (nostr-tools 2.22) Design: - 4px grid spacing system - Glass morphism UI components - Netflix-style hero section with featured content - Smooth animations and hover effects - Mobile-first responsive breakpoints - Dark theme with custom color palette Content: - 20+ IndeeHub films with titles, descriptions, categories - Bitcoin documentaries: God Bless Bitcoin, Dirty Coin, Searching for Satoshi - Independent films and documentaries - Working Unsplash CDN images for thumbnails and backdrops Ready for deployment to Umbrel, Start9, and Archy nodes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
57
src/stores/content.ts
Normal file
57
src/stores/content.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { Content } from '../types/content'
|
||||
import { indeeHubFilms, bitcoinFilms, documentaries, dramas } from '../data/indeeHubFilms'
|
||||
|
||||
export const useContentStore = defineStore('content', () => {
|
||||
const featuredContent = ref<Content | null>(null)
|
||||
const contentRows = ref<{ [key: string]: Content[] }>({
|
||||
featured: [],
|
||||
newReleases: [],
|
||||
bitcoin: [],
|
||||
documentaries: [],
|
||||
dramas: [],
|
||||
independent: []
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
async function fetchContent() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
// Simulate loading delay for UX
|
||||
await new Promise(resolve => setTimeout(resolve, 300))
|
||||
|
||||
// Set featured content (first Bitcoin doc)
|
||||
featuredContent.value = bitcoinFilms[0] || indeeHubFilms[0]
|
||||
|
||||
// Organize content into rows
|
||||
contentRows.value = {
|
||||
featured: indeeHubFilms.slice(0, 10),
|
||||
newReleases: indeeHubFilms.slice(0, 8).reverse(),
|
||||
bitcoin: bitcoinFilms,
|
||||
documentaries: documentaries.slice(0, 10),
|
||||
dramas: dramas.slice(0, 10),
|
||||
independent: indeeHubFilms.filter(f =>
|
||||
!f.categories.includes('Bitcoin') && !f.categories.includes('Documentary')
|
||||
).slice(0, 10)
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = 'Failed to load content'
|
||||
console.error(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
featuredContent,
|
||||
contentRows,
|
||||
loading,
|
||||
error,
|
||||
fetchContent
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user