Enhance content management and user interaction features

- Introduced a new content source toggle in the profile and app header to switch between IndeeHub and TopDoc films.
- Updated the content fetching logic to dynamically load content based on the selected source.
- Enhanced the seeding process to include a combined catalog of IndeeHub and TopDoc films, ensuring diverse content availability.
- Improved user interaction by preventing duplicate reactions and ensuring a smoother voting experience across comments and content.
- Added support for Amber login (NIP-55) for Android users, integrating it into the existing authentication flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-12 14:24:52 +00:00
parent ab0560de00
commit 35bc78b890
38 changed files with 1107 additions and 185 deletions

View File

@@ -177,11 +177,11 @@
<h2 class="content-row-title text-xl md:text-2xl font-bold text-white mb-4 px-4 uppercase">
{{ activeAlgorithmLabel }}
</h2>
<div class="flex gap-8 overflow-x-auto overflow-y-visible scrollbar-hide scroll-smooth px-4 pt-6 pb-8 flex-wrap">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4 md:gap-6 lg:gap-8 px-4 pt-6 pb-8">
<div
v-for="content in filteredContent"
:key="content.id"
class="content-card flex-shrink-0 w-[200px] md:w-[280px] group/card cursor-pointer"
class="content-card group/card cursor-pointer"
@click="handleContentClick(content)"
>
<div class="glass-card rounded-lg p-1.5 transition-all duration-300">
@@ -193,8 +193,8 @@
/>
</div>
<div class="mt-2">
<h3 class="text-base md:text-xl font-semibold md:font-bold text-white truncate">{{ content.title }}</h3>
<p class="text-base text-white/60 truncate hidden md:block">{{ content.description }}</p>
<h3 class="text-sm md:text-xl font-semibold md:font-bold text-white truncate">{{ content.title }}</h3>
<p class="text-xs md:text-base text-white/60 line-clamp-2 md:truncate">{{ content.description }}</p>
</div>
</div>
</div>
@@ -277,7 +277,8 @@ import { useContentStore } from '../stores/content'
import { useAuth } from '../composables/useAuth'
import { useAccounts } from '../composables/useAccounts'
import { useContentDiscovery } from '../composables/useContentDiscovery'
import { indeeHubFilms, bitcoinFilms, documentaries } from '../data/indeeHubFilms'
// indeeHubFilms data is now loaded dynamically via the content store
import { useContentSourceStore } from '../stores/contentSource'
import type { Content } from '../types/content'
const emit = defineEmits<{ (e: 'openAuth', redirect?: string): void }>()
@@ -343,24 +344,35 @@ const continueWatching = ref<Array<{ content: Content; progress: number }>>([])
const myListContent = ref<Content[]>([])
const rentedContent = ref<Content[]>([])
const contentSourceStore = useContentSourceStore()
let lastLoadedSource: string | null = null
/**
* Populate library with dummy data from the film catalog.
* Populate library with dummy data from the current content catalog.
* Re-runs when the content source changes so My List reflects the active catalog.
* In production this would come from the API.
*/
function loadDummyLibrary() {
if (myListContent.value.length > 0) return // Already loaded
const source = contentSourceStore.activeSource
if (myListContent.value.length > 0 && lastLoadedSource === source) return
lastLoadedSource = source
continueWatching.value = indeeHubFilms.slice(0, 3).map((film) => ({
const rows = contentStore.contentRows
const featured = rows.featured || []
const btc = rows.bitcoin || []
const docs = rows.documentaries || []
continueWatching.value = featured.slice(0, 3).map((film) => ({
content: film,
progress: Math.floor(Math.random() * 70) + 10,
}))
myListContent.value = [
...bitcoinFilms.slice(0, 3),
...indeeHubFilms.slice(5, 8),
...btc.slice(0, 3),
...featured.slice(5, 8),
]
rentedContent.value = documentaries.slice(0, 2)
rentedContent.value = docs.slice(0, 2)
}
// If someone navigates directly to /library without being logged in,