From 0bb1bcc5f9aca5b1ed64eab1deb6dc362f9c1a8e Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 2 Feb 2026 22:19:47 +0000 Subject: [PATCH] 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 --- .cursor/mcp.json | 37 + .cursor/rules/accessibility.mdc | 281 ++ .cursor/rules/animation-principles.mdc | 69 + .cursor/rules/code-quality.mdc | 239 ++ .cursor/rules/component-architecture.mdc | 79 + .cursor/rules/git-workflow.mdc | 172 ++ .cursor/rules/master-philosophy.mdc | 109 + .cursor/rules/mobile-ux-patterns.mdc | 118 + .cursor/rules/performance-optimization.mdc | 224 ++ .cursor/rules/quick-reference.mdc | 183 ++ .cursor/rules/scroll-navigation.mdc | 111 + .cursor/rules/seo-meta-strategy.mdc | 112 + .cursor/rules/tailwind-mastery.mdc | 156 ++ .cursor/rules/theme-architecture.mdc | 152 ++ .cursor/rules/visual-design-system.mdc | 166 ++ .cursor/rules/vue-conventions.mdc | 200 ++ .gitignore | 32 + CONTENT-INTEGRATION-COMPLETE.md | 176 ++ CURSOR-MCP-SETUP.md | 151 ++ FINAL-STATUS.md | 244 ++ FIXES-APPLIED.md | 102 + INDEEHHUB-INTEGRATION.md | 78 + PROJECT-COMPLETE.md | 214 ++ PROJECT-SUMMARY.md | 195 ++ README.md | 99 + assets/README.md | 45 + assets/images/logo.svg | 131 + extract-films.js | 25 + index.html | 14 + package-lock.json | 2835 ++++++++++++++++++++ package.json | 29 + postcss.config.js | 6 + src/App.vue | 12 + src/components/ContentRow.vue | 117 + src/components/MobileNav.vue | 79 + src/components/VideoPlayer.vue | 233 ++ src/composables/useMobile.ts | 84 + src/data/indeeHubFilms.ts | 231 ++ src/env.d.ts | 5 + src/main.ts | 12 + src/router/index.ts | 15 + src/stores/content.ts | 57 + src/style.css | 124 + src/types/content.ts | 34 + src/utils/indeeHubApi.ts | 97 + src/utils/nostr.ts | 100 + src/views/Browse.vue | 185 ++ tailwind.config.js | 63 + tsconfig.json | 30 + vite.config.ts | 16 + 50 files changed, 8278 insertions(+) create mode 100644 .cursor/mcp.json create mode 100644 .cursor/rules/accessibility.mdc create mode 100644 .cursor/rules/animation-principles.mdc create mode 100644 .cursor/rules/code-quality.mdc create mode 100644 .cursor/rules/component-architecture.mdc create mode 100644 .cursor/rules/git-workflow.mdc create mode 100644 .cursor/rules/master-philosophy.mdc create mode 100644 .cursor/rules/mobile-ux-patterns.mdc create mode 100644 .cursor/rules/performance-optimization.mdc create mode 100644 .cursor/rules/quick-reference.mdc create mode 100644 .cursor/rules/scroll-navigation.mdc create mode 100644 .cursor/rules/seo-meta-strategy.mdc create mode 100644 .cursor/rules/tailwind-mastery.mdc create mode 100644 .cursor/rules/theme-architecture.mdc create mode 100644 .cursor/rules/visual-design-system.mdc create mode 100644 .cursor/rules/vue-conventions.mdc create mode 100644 .gitignore create mode 100644 CONTENT-INTEGRATION-COMPLETE.md create mode 100644 CURSOR-MCP-SETUP.md create mode 100644 FINAL-STATUS.md create mode 100644 FIXES-APPLIED.md create mode 100644 INDEEHHUB-INTEGRATION.md create mode 100644 PROJECT-COMPLETE.md create mode 100644 PROJECT-SUMMARY.md create mode 100644 README.md create mode 100644 assets/README.md create mode 100644 assets/images/logo.svg create mode 100644 extract-films.js create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 src/App.vue create mode 100644 src/components/ContentRow.vue create mode 100644 src/components/MobileNav.vue create mode 100644 src/components/VideoPlayer.vue create mode 100644 src/composables/useMobile.ts create mode 100644 src/data/indeeHubFilms.ts create mode 100644 src/env.d.ts create mode 100644 src/main.ts create mode 100644 src/router/index.ts create mode 100644 src/stores/content.ts create mode 100644 src/style.css create mode 100644 src/types/content.ts create mode 100644 src/utils/indeeHubApi.ts create mode 100644 src/utils/nostr.ts create mode 100644 src/views/Browse.vue create mode 100644 tailwind.config.js create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.cursor/mcp.json b/.cursor/mcp.json new file mode 100644 index 0000000..d532fdf --- /dev/null +++ b/.cursor/mcp.json @@ -0,0 +1,37 @@ +{ + "mcpServers": { + "filesystem": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-filesystem@2026.1.14", + "/Users/dorian/Projects" + ] + }, + "memory": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-memory@2026.1.26" + ] + }, + "nostr": { + "command": "npx", + "args": [ + "-y", + "nostr-mcp-server@2.1.0" + ], + "env": { + "NOSTR_NSEC_KEY": "nsec1tzud8sr2m4nl49762yuqzgmanf93e23e4d0d3euraaqc2t677unqawmzec", + "NOSTR_RELAYS": "wss://relay.damus.io,wss://nos.lol,wss://relay.nostr.band" + } + }, + "puppeteer": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-puppeteer@2025.5.12" + ] + } + } +} diff --git a/.cursor/rules/accessibility.mdc b/.cursor/rules/accessibility.mdc new file mode 100644 index 0000000..206c16c --- /dev/null +++ b/.cursor/rules/accessibility.mdc @@ -0,0 +1,281 @@ +--- +description: WCAG AA accessibility standards and patterns +alwaysApply: false +globs: **/*.{vue,html,jsx,tsx} +--- + +# Accessibility Standards (A11y) + +## Philosophy + +Accessible design is not optional. It's a fundamental requirement for building inclusive, usable applications. + +**Target: WCAG AA Compliance** + +## Color & Contrast + +### Contrast Ratios (WCAG AA) +- **Normal text**: 4.5:1 minimum +- **Large text** (18pt+): 3:1 minimum +- **UI components**: 3:1 minimum + +```html + +
+ Readable text with 21:1 ratio +
+ + +
+ Hard to read - only 1.5:1 ratio +
+``` + +### Don't Rely on Color Alone + +```html + + + + Error: Invalid input + +``` + +## Semantic HTML + +### Use the Right Elements + +```html + +
+ +
+ +
+
+

Article Title

+

Content...

+
+
+ + +
+ +
+``` + +### Heading Hierarchy + +```html + +

Page Title

+

Section Title

+

Subsection Title

+``` + +## Keyboard Navigation + +### Focus Indicators + +**Always show visible focus states.** + +```html + + + +``` + +### Skip Links + +```html + + Skip to main content + + +
+ +
+``` + +### Test Keyboard Navigation +- Tab through entire page +- Shift+Tab to go backwards +- Enter/Space to activate buttons +- Escape to close modals/dropdowns + +## ARIA (Use Sparingly) + +**First rule of ARIA: Don't use ARIA if you can use semantic HTML instead.** + +### ARIA Labels + +```html + + + + + +``` + +### ARIA Live Regions + +```html + +
+ {{ statusMessage }} +
+``` + +## Forms Accessibility + +### Label Every Input + +```html + + + + + + +``` + +### Required Fields + +```html + + +``` + +### Error Messages + +```html + + + +``` + +## Touch Targets & Mobile + +### Minimum Touch Target Size + +**WCAG Guideline: 44x44px minimum** + +```html + + + + + +``` + +### Spacing Between Targets + +```html + + +``` + +## Motion & Animation + +### Respect Prefers-Reduced-Motion + +```css +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} +``` + +## Screen Reader Support + +### Alt Text for Images + +```html + +Bar chart showing 25% revenue increase + + + +``` + +### Screen Reader Only Text + +```css +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} +``` + +## Accessibility Checklist + +### Perceivable +- ✅ Text has sufficient contrast (4.5:1) +- ✅ Images have alt text +- ✅ Color is not the only indicator +- ✅ Content works at 200% zoom + +### Operable +- ✅ All functionality keyboard accessible +- ✅ Focus indicators visible +- ✅ No keyboard traps +- ✅ Touch targets at least 44x44px + +### Understandable +- ✅ Clear, simple language +- ✅ Labels for all form inputs +- ✅ Error messages are clear +- ✅ Consistent navigation + +### Robust +- ✅ Semantic HTML +- ✅ Valid ARIA attributes +- ✅ Works with assistive technologies + +**Remember: Accessibility is not a checklist—it's an ongoing commitment to inclusive design.** diff --git a/.cursor/rules/animation-principles.mdc b/.cursor/rules/animation-principles.mdc new file mode 100644 index 0000000..a7b8cd8 --- /dev/null +++ b/.cursor/rules/animation-principles.mdc @@ -0,0 +1,69 @@ +--- +description: Animation timing, easing, stagger patterns, and motion design principles +alwaysApply: false +globs: **/*.{ts,tsx,js,jsx,vue,css,scss} +--- + +# Animation Principles & Motion Design + +## Core Philosophy + +Every animation should serve one of these purposes: +- **Guide Attention**: Direct user focus to important elements +- **Provide Feedback**: Confirm actions and state changes +- **Show Relationships**: Reveal spatial and hierarchical connections +- **Enhance Perception**: Make loading and transitions feel faster +- **Add Delight**: Create memorable micro-interactions + +## Duration Guidelines + +```javascript +const durations = { + instant: 100, // Micro-feedback (hover states) + fast: 200, // Small elements (tooltips, dropdowns) + moderate: 300, // Standard UI transitions (modals, cards) + normal: 500, // Page sections, complex components + slow: 600, // Hero animations, page transitions +}; +``` + +## Easing Functions + +- **ease-out**: 90% of entrance animations (fade in, slide in) +- **ease-in**: Exit animations (fade out, slide out) +- **ease-in-out**: Position changes, transforms +- **spring**: Playful interactions, emphasis +- **linear**: Progress bars, loading spinners + +## Staggered Animation Pattern + +```javascript +// Delay calculation +const staggerDelay = (index, baseDelay = 100) => index * baseDelay; +``` + +Guidelines: +- Delay increment: 50-150ms between items +- Max items: Limit to 6-8 visible items +- Direction: Top-to-bottom or left-to-right + +## Reduced Motion Accessibility + +Always respect `prefers-reduced-motion` settings: + +```css +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} +``` + +## Performance + +- ✅ Animate `transform` and `opacity` only +- ✅ Use `will-change` sparingly +- ✅ Limit simultaneous animations +- ❌ Don't animate `width`, `height`, `top`, `left` diff --git a/.cursor/rules/code-quality.mdc b/.cursor/rules/code-quality.mdc new file mode 100644 index 0000000..dd518f4 --- /dev/null +++ b/.cursor/rules/code-quality.mdc @@ -0,0 +1,239 @@ +--- +description: Code quality principles and clean code practices +alwaysApply: true +--- + +# Code Quality & Clean Code Standards + +## Core Principles + +### 1. Readability First + +Code is read far more often than it's written. + +```javascript +// ❌ Bad - Unclear, cryptic +const d = new Date() +const y = d.getFullYear() + +// ✅ Good - Clear, self-documenting +const today = new Date() +const year = today.getFullYear() +``` + +### 2. Single Responsibility Principle + +Each function/component should do one thing well. + +```javascript +// ✅ Good - Single responsibility +function validateEmail(email) { + return email && email.length > 0 +} + +function formatEmail(email) { + return email.toLowerCase().trim() +} +``` + +### 3. DRY (Don't Repeat Yourself) + +Extract repeated logic into reusable functions. + +### 4. Meaningful Names + +Names should reveal intent. + +```javascript +// ❌ Bad +const d = 86400000 +const arr = [] + +// ✅ Good +const MILLISECONDS_PER_DAY = 86400000 +const activeProjects = [] +``` + +### 5. Keep It Simple (KISS) + +Simplicity is the ultimate sophistication. + +## Error Handling + +### Always Handle Errors + +```javascript +// ✅ Good - Comprehensive error handling +async function fetchProjects() { + const error = ref(null) + const isLoading = ref(true) + const data = ref(null) + + try { + const response = await fetch('/api/projects') + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + data.value = await response.json() + } catch (err) { + error.value = err.message + console.error('Failed to fetch projects:', err) + } finally { + isLoading.value = false + } + + return { data, error, isLoading } +} +``` + +### User-Friendly Error Messages + +```javascript +function getErrorMessage(error) { + const messages = { + 'ERR_CONNECTION_REFUSED': 'Unable to connect. Please check your internet.', + 'ERR_TIMEOUT': 'Request timed out. Please try again.', + } + + return messages[error.code] || 'An unexpected error occurred.' +} +``` + +## Comments & Documentation + +### When to Comment + +#### ✅ DO Comment: +- **Why** something is done (not what) +- Complex algorithms +- Non-obvious decisions +- Workarounds for bugs + +```javascript +// ✅ Good - Explains WHY +// We use a 300ms debounce to avoid overwhelming the API +// with requests while the user is still typing +const debouncedSearch = debounce(searchProjects, 300) +``` + +#### ❌ DON'T Comment: +- Obvious code +- Outdated information +- Commented-out code (delete it instead) + +### JSDoc for Public APIs + +```javascript +/** + * Formats a date into human-readable format + * + * @param {string|Date} date - The date to format + * @param {Object} options - Formatting options + * @returns {string} Formatted date string + * + * @example + * formatDate('2026-02-02', { format: 'long' }) + * // Returns: "February 2, 2026" + */ +export function formatDate(date, options = {}) { + // Implementation +} +``` + +## Import Order + +```javascript +// 1. External libraries +import { ref, computed } from 'vue' +import { useRouter } from 'vue-router' + +// 2. Internal modules +import { useAuth } from '@/composables/useAuth' +import { formatDate } from '@/utils/date' + +// 3. Components +import Button from '@/components/atoms/Button.vue' + +// 4. Styles +import './styles.css' +``` + +## Code Review Checklist + +### Before Submitting PR +- ✅ Code runs without errors +- ✅ Tests pass +- ✅ No console errors or warnings +- ✅ Linter passes +- ✅ Code follows conventions +- ✅ Complex logic is commented +- ✅ No commented-out code +- ✅ Mobile responsive +- ✅ Accessibility checked + +### What to Look For in Review +- **Correctness**: Does it work as intended? +- **Readability**: Is it easy to understand? +- **Maintainability**: Can it be easily modified? +- **Performance**: Any obvious bottlenecks? +- **Security**: Any vulnerabilities? +- **Testing**: Adequate test coverage? + +## Common Patterns + +### Guard Clauses + +```javascript +// ✅ Good - Early returns +function processUser(user) { + if (!user) return null + if (!user.email) return null + if (!user.isActive) return null + + // Main logic here + return processedUser +} +``` + +### Avoid Nested Ifs + +```javascript +// ❌ Bad +if (user) { + if (user.isActive) { + if (user.hasPermission) { + // Do something + } + } +} + +// ✅ Good +if (!user) return +if (!user.isActive) return +if (!user.hasPermission) return + +// Do something +``` + +## Summary Checklist + +### Code +- ✅ Readable and self-documenting +- ✅ Single responsibility +- ✅ DRY (no repetition) +- ✅ Meaningful names +- ✅ Simple and clear + +### Error Handling +- ✅ All errors caught +- ✅ User-friendly messages +- ✅ Logged appropriately + +### Documentation +- ✅ Complex logic commented +- ✅ Public APIs documented +- ✅ No outdated comments + +**Remember: Quality is not an act, it's a habit.** diff --git a/.cursor/rules/component-architecture.mdc b/.cursor/rules/component-architecture.mdc new file mode 100644 index 0000000..c8bae7d --- /dev/null +++ b/.cursor/rules/component-architecture.mdc @@ -0,0 +1,79 @@ +--- +description: Component composition patterns and architecture principles +alwaysApply: false +globs: **/*.{ts,tsx,js,jsx,vue,svelte} +--- + +# Component Architecture & Composition Patterns + +## Core Philosophy + +**Composition Over Configuration** + +Build complex UIs from simple, focused components that compose well together. + +### Key Tenets + +- **Single Responsibility**: Each component does one thing well +- **Composition Slots**: Use children/slots instead of complex prop APIs +- **Default Props**: Provide sensible defaults for easy use +- **Prop Interfaces**: Clear contracts with TypeScript/PropTypes +- **Minimal State**: Keep component state local and minimal + +## Anti-patterns to Avoid + +- ❌ God components that do everything +- ❌ Prop drilling through many layers +- ❌ Hard-coded values instead of props +- ❌ Component logic mixed with layout +- ❌ Tight coupling between components + +## Template Pattern + +Create base templates that handle common layouts and let content be injected. + +```jsx +const PageTemplate = ({ title, children }) => ( +
+
+
+ {title &&

{title}

} + {children} +
+
+
+); +``` + +## Container/Presenter Pattern + +Split components into smart (containers) and dumb (presenters) components. + +- **Container**: Handles data and logic +- **Presenter**: Pure presentation, receives data via props + +## Prop Interface Design + +```typescript +interface BaseComponentProps { + className?: string; + children?: React.ReactNode; + testId?: string; +} + +interface ButtonProps extends BaseComponentProps { + variant?: 'primary' | 'secondary' | 'ghost'; + size?: 'sm' | 'md' | 'lg'; + disabled?: boolean; + loading?: boolean; + onClick?: (event: React.MouseEvent) => void; +} +``` + +### Prop Naming Conventions + +- Boolean props: `isOpen`, `hasError`, `disabled` +- Handler props: `onClick`, `onClose`, `onChange` +- Render props: `renderHeader`, `renderItem` +- Data props: `items`, `data`, `value` +- Config props: `variant`, `size`, `theme` diff --git a/.cursor/rules/git-workflow.mdc b/.cursor/rules/git-workflow.mdc new file mode 100644 index 0000000..c1b726d --- /dev/null +++ b/.cursor/rules/git-workflow.mdc @@ -0,0 +1,172 @@ +--- +description: Git workflow and commit message conventions +alwaysApply: false +globs: .git/** +--- + +# Git Workflow & Version Control + +## Commit Message Format + +``` +(): + + + +