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>
184 lines
3.4 KiB
Plaintext
184 lines
3.4 KiB
Plaintext
---
|
|
description: Quick reference for common patterns and commands
|
|
alwaysApply: false
|
|
globs: **/*.{vue,js,ts,html}
|
|
---
|
|
|
|
# Quick Reference Guide
|
|
|
|
## Vue 3 Composition API Template
|
|
|
|
```vue
|
|
<template>
|
|
<div>{{ message }}</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
|
|
// Props
|
|
const props = defineProps({
|
|
title: String
|
|
})
|
|
|
|
// Emits
|
|
const emit = defineEmits(['update'])
|
|
|
|
// State
|
|
const message = ref('Hello')
|
|
|
|
// Computed
|
|
const displayMessage = computed(() => message.value.toUpperCase())
|
|
|
|
// Methods
|
|
const handleClick = () => {
|
|
emit('update', { value: message.value })
|
|
}
|
|
|
|
// Lifecycle
|
|
onMounted(() => {
|
|
console.log('Component mounted')
|
|
})
|
|
</script>
|
|
```
|
|
|
|
## Tailwind Quick Classes
|
|
|
|
### Layout
|
|
```html
|
|
<div class="flex items-center justify-between gap-4">
|
|
<div class="grid grid-cols-3 gap-6">
|
|
<div class="max-w-7xl mx-auto px-4">
|
|
```
|
|
|
|
### Spacing (4px grid)
|
|
```html
|
|
<div class="p-4"> <!-- 16px all sides -->
|
|
<div class="px-6 py-3"> <!-- 24px H, 12px V -->
|
|
<div class="mb-6"> <!-- 24px bottom -->
|
|
```
|
|
|
|
### Typography
|
|
```html
|
|
<p class="text-sm"> <!-- 14px -->
|
|
<p class="text-base"> <!-- 16px -->
|
|
<p class="text-xl"> <!-- 20px -->
|
|
<p class="font-semibold"> <!-- 600 -->
|
|
<p class="font-bold"> <!-- 700 -->
|
|
```
|
|
|
|
### Responsive
|
|
```html
|
|
<div class="text-base md:text-lg lg:text-xl">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
|
<div class="hidden md:block"> <!-- Desktop only -->
|
|
<div class="block md:hidden"> <!-- Mobile only -->
|
|
```
|
|
|
|
## Common Component Patterns
|
|
|
|
### Button
|
|
```html
|
|
<button class="px-6 py-3 bg-primary text-white rounded-lg font-semibold
|
|
hover:bg-primary-dark transition-colors">
|
|
Click Me
|
|
</button>
|
|
```
|
|
|
|
### Input
|
|
```html
|
|
<input
|
|
type="text"
|
|
class="w-full px-4 py-2.5 border border-gray-300 rounded-lg
|
|
focus:border-primary focus:ring-2 focus:ring-primary-focus"
|
|
/>
|
|
```
|
|
|
|
### Card
|
|
```html
|
|
<div class="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow">
|
|
<h3 class="text-xl font-semibold mb-2">Title</h3>
|
|
<p class="text-gray-600">Content</p>
|
|
</div>
|
|
```
|
|
|
|
## Error Handling Pattern
|
|
|
|
```javascript
|
|
async function fetchData() {
|
|
const error = ref(null)
|
|
const isLoading = ref(true)
|
|
const data = ref(null)
|
|
|
|
try {
|
|
const response = await fetch('/api/data')
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
data.value = await response.json()
|
|
} catch (err) {
|
|
error.value = err.message
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
|
|
return { data, error, isLoading }
|
|
}
|
|
```
|
|
|
|
## Git Commands
|
|
|
|
```bash
|
|
# Daily workflow
|
|
git status
|
|
git checkout -b feature/new-feature
|
|
git add .
|
|
git commit -m "feat: add feature"
|
|
git push origin feature/new-feature
|
|
|
|
# Undo changes
|
|
git restore .
|
|
|
|
# Stash
|
|
git stash
|
|
git stash pop
|
|
```
|
|
|
|
## Performance Targets
|
|
|
|
```
|
|
LCP (Largest Contentful Paint): < 2.5s
|
|
FID (First Input Delay): < 100ms
|
|
CLS (Cumulative Layout Shift): < 0.1
|
|
Bundle Size: < 200KB gzipped
|
|
```
|
|
|
|
## Accessibility Quick Checks
|
|
|
|
- [ ] Images have alt text
|
|
- [ ] Color contrast ≥ 4.5:1
|
|
- [ ] Keyboard navigation works
|
|
- [ ] Focus indicators visible
|
|
- [ ] Form labels present
|
|
- [ ] Touch targets ≥ 44x44px
|
|
|
|
## Responsive Breakpoints
|
|
|
|
```
|
|
sm: 640px // Tablet
|
|
md: 768px // Desktop
|
|
lg: 1024px // Large
|
|
xl: 1280px // XL
|
|
```
|
|
|
|
## Common Regex Patterns
|
|
|
|
```javascript
|
|
// Email
|
|
/^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
|
|
// URL
|
|
/^https?:\/\/.+/
|
|
|
|
// Hex color
|
|
/^#[0-9A-Fa-f]{6}$/
|
|
```
|