project context update
This commit is contained in:
+62
-248
@@ -15,10 +15,9 @@ Content is sourced from the pre-1980s Vedabase, extracted and indexed into Mongo
|
|||||||
- **shadcn/ui** (base-nova style, lucide icons) — components: Button, Card, Badge, Tooltip, Input, Drawer
|
- **shadcn/ui** (base-nova style, lucide icons) — components: Button, Card, Badge, Tooltip, Input, Drawer
|
||||||
- **next-themes** for dark/light/system mode
|
- **next-themes** for dark/light/system mode
|
||||||
- **vaul** for mobile drawer navigation
|
- **vaul** for mobile drawer navigation
|
||||||
- **Prisma v6** with MongoDB (provider `prisma-client-js`)
|
- **Go BFF API** — all data fetched via `lib/bff.ts` HTTP client calling the Go BFF server (no direct database access)
|
||||||
- **MongoDB** native driver (`mongodb` package) for seeding (Prisma requires replica set for writes)
|
- **framer-motion** for audio player animations (spring enter/exit, minimize/expand transitions, audio wave bars)
|
||||||
- **Python 3** with BeautifulSoup4 + `indic-transliteration` for HTML extraction scripts
|
- **Python 3** with BeautifulSoup4 + `indic-transliteration` for HTML extraction scripts
|
||||||
- **Database**: MongoDB at `DATABASE_URL` env variable with `?authSource=admin`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -96,23 +95,21 @@ knowledgebase/
|
|||||||
│ ├── logo.tsx → Theme-aware logo component
|
│ ├── logo.tsx → Theme-aware logo component
|
||||||
│ └── theme-provider.tsx → next-themes wrapper
|
│ └── theme-provider.tsx → next-themes wrapper
|
||||||
├── lib/
|
├── lib/
|
||||||
│ ├── db.ts → Prisma client singleton
|
│ ├── bff.ts → BFF API client (typed fetch wrapper: bff<T>(), bffList<T>(), bffOrThrow<T>())
|
||||||
│ ├── api.ts → Core data access (books, verses, prose chapters, glossary)
|
│ ├── api.ts → Core data access (books, verses, prose chapters, glossary) — calls BFF API
|
||||||
|
│ ├── books.ts → Generic book data layer (replaces 29 individual book files)
|
||||||
│ ├── constants.ts → Shared constants (BOOK_NAMES, CC_LILAS)
|
│ ├── constants.ts → Shared constants (BOOK_NAMES, CC_LILAS)
|
||||||
│ ├── og.ts → OG image metadata builders (ogForVerse, ogForLetter, etc.)
|
│ ├── og.ts → OG image metadata builders (ogForVerse, ogForLetter, etc.)
|
||||||
│ ├── text-highlight.ts → Text fragment encode/decode, highlight matching
|
│ ├── text-highlight.ts → Text fragment encode/decode, highlight matching
|
||||||
│ ├── source-reference.ts → Source reference from URL (for copy attribution)
|
│ ├── source-reference.ts → Source reference from URL (for copy attribution)
|
||||||
│ ├── disciples.ts → Disciples data access (by letter, place, year, search)
|
│ ├── disciples.ts → Disciples data access — calls BFF API
|
||||||
│ ├── letters.ts → Letters data access (by year, recipient, location)
|
│ ├── letters.ts → Letters data access (by year, recipient, location) — calls BFF API
|
||||||
│ ├── transcriptions.ts → Transcriptions data access (reads from Prisma/MongoDB)
|
│ ├── transcriptions.ts → Transcriptions data access — calls BFF API
|
||||||
│ ├── utils.ts → cn() helper
|
│ ├── utils.ts → cn() helper
|
||||||
│ ├── [book].ts → Per-book data access layers (nod, tlc, iso, noi, ej, ek, etc.)
|
│ ├── [book].ts → Per-book data access layers (nod, tlc, iso, noi, ej, ek, etc.) — calls BFF API
|
||||||
│ ├── other-documents.ts → Other Documents data access
|
│ ├── other-documents.ts → Other Documents data access — calls BFF API
|
||||||
│ ├── journals.ts → Journals data access
|
│ ├── journals.ts → Journals data access — calls BFF API
|
||||||
│ └── magazines.ts → Magazines data access
|
│ └── magazines.ts → Magazines data access — calls BFF API
|
||||||
├── prisma/
|
|
||||||
│ └── schema.prisma → All models (Verse, BookMeta, ProseChapter, Essay, Letter,
|
|
||||||
│ GlossaryEntry, Disciple, Transcription, etc.)
|
|
||||||
└── public/
|
└── public/
|
||||||
├── fonts/Noto_Sans/static/ → NotoSans-Regular.ttf + NotoSans-Bold.ttf (OG images)
|
├── fonts/Noto_Sans/static/ → NotoSans-Regular.ttf + NotoSans-Bold.ttf (OG images)
|
||||||
├── images/ → OG card image (Prabhupāda)
|
├── images/ → OG card image (Prabhupāda)
|
||||||
@@ -132,232 +129,50 @@ extractor/ → Extraction & seeding tools (not deployed)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Database Schema (Prisma + MongoDB)
|
## Data Architecture
|
||||||
|
|
||||||
```prisma
|
The knowledgebase **never connects to MongoDB directly**. All data is served by the **Go BFF API** server.
|
||||||
type Synonym {
|
|
||||||
word String
|
|
||||||
meanings String[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model Verse {
|
### BFF Server
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String // "bg" | "sb" | "cc" | "sb1962" | "iso" | "noi"
|
|
||||||
division String? // null for BG/SB1962/ISO/NOI; canto for SB; lila for CC
|
|
||||||
chapter Int
|
|
||||||
verse Int
|
|
||||||
verseEnd Int?
|
|
||||||
reference String
|
|
||||||
bookTitle String
|
|
||||||
devanagari String
|
|
||||||
bengali String? // only CC has Bengali
|
|
||||||
transliteration String
|
|
||||||
synonyms Synonym[]
|
|
||||||
translation String
|
|
||||||
purport String[]
|
|
||||||
|
|
||||||
@@unique([book, division, chapter, verse])
|
- **URL**: Configured via `BFF_URL` environment variable (default: `http://localhost:8080`)
|
||||||
@@index([book])
|
- The BFF reads from MongoDB — the knowledgebase frontend has no database driver or connection string
|
||||||
@@index([book, division])
|
- All API endpoints live under `/api/v1/...` on the BFF server
|
||||||
@@index([book, division, chapter])
|
|
||||||
@@map("verses")
|
|
||||||
}
|
|
||||||
|
|
||||||
model BookMeta {
|
### BFF Client (`lib/bff.ts`)
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String @unique
|
|
||||||
data Json
|
|
||||||
|
|
||||||
@@map("book_meta")
|
The typed fetch wrapper provides three helpers:
|
||||||
}
|
|
||||||
|
|
||||||
model ProseChapter {
|
- **`bff<T>(path, options?)`** — Fetch JSON from the BFF. Returns `null` on 404, throws `BffError` on other failures.
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
- **`bffList<T>(path, options?)`** — Fetch a list. Returns `[]` on 404 (instead of null).
|
||||||
book String
|
- **`bffOrThrow<T>(path, options?)`** — Fetch JSON, throwing on 404. Use when a missing resource should be an error.
|
||||||
volume Int // 0 = no volumes (sentinel for non-volume books)
|
|
||||||
chapter Int? // null for intro segments
|
|
||||||
title String
|
|
||||||
type String // "chapter" | "intro-segment" | "conclusion"
|
|
||||||
slug String
|
|
||||||
order Int
|
|
||||||
paragraphs String[]
|
|
||||||
|
|
||||||
@@unique([book, volume, slug])
|
Options include `params` (query parameters), `revalidate` (Next.js ISR seconds, default 60), and `tags` (cache tags).
|
||||||
@@index([book])
|
|
||||||
@@index([book, volume])
|
|
||||||
@@index([book, volume, type])
|
|
||||||
@@map("prose_chapters")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Essay {
|
### Response Envelope
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
slug String @unique
|
|
||||||
title String
|
|
||||||
author String
|
|
||||||
year Int?
|
|
||||||
group String? // e.g., "two-essays"
|
|
||||||
order Int
|
|
||||||
paragraphs String[]
|
|
||||||
|
|
||||||
@@index([group])
|
BFF responses use a `{ success: true, data: ... }` envelope. The `bff()` client auto-unwraps this — callers receive the inner `data` value directly.
|
||||||
@@map("essays")
|
|
||||||
}
|
|
||||||
|
|
||||||
model OtherDocumentMeta {
|
### Case Mapping
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String @unique
|
|
||||||
data Json
|
|
||||||
|
|
||||||
@@map("other_document_meta")
|
The BFF uses **snake_case** JSON field names (Go convention). Each frontend data layer file (`lib/letters.ts`, `lib/transcriptions.ts`, `lib/books.ts`, etc.) maps BFF responses to **camelCase** TypeScript types used by React components.
|
||||||
}
|
|
||||||
|
|
||||||
model OtherDocumentChapter {
|
### Data Layer Files
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String
|
|
||||||
chapter Int
|
|
||||||
title String
|
|
||||||
type String
|
|
||||||
slug String
|
|
||||||
order Int
|
|
||||||
paragraphs String[]
|
|
||||||
|
|
||||||
@@unique([book, slug])
|
Individual `lib/*.ts` files are thin wrappers that:
|
||||||
@@index([book])
|
1. Call a BFF endpoint via `bff()` / `bffList()` / `bffOrThrow()`
|
||||||
@@map("other_document_chapters")
|
2. Map the snake_case response to camelCase frontend types
|
||||||
}
|
3. Export typed functions consumed by Next.js server components
|
||||||
|
|
||||||
model JournalMeta {
|
Key data layers and their BFF endpoint prefixes:
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
- `lib/api.ts` → `/api/v1/books/*`, `/api/v1/glossary/*` — Books, verses, prose chapters, glossary
|
||||||
book String @unique
|
- `lib/books.ts` → `/api/v1/books/{code}/*` — Generic book data layer (replaces 29 individual per-book files)
|
||||||
data Json
|
- `lib/letters.ts` → `/api/v1/letters/*` — Letters (by year, recipient, location)
|
||||||
|
- `lib/transcriptions.ts` → `/api/v1/transcriptions/*` — Transcriptions (by year, place, type)
|
||||||
@@map("journal_meta")
|
- `lib/disciples.ts` → `/api/v1/disciples/*` — Disciples directory
|
||||||
}
|
- `lib/other-documents.ts` → `/api/v1/other-documents/*` — Other Documents
|
||||||
|
- `lib/journals.ts` → `/api/v1/journals/*` — Journals
|
||||||
model JournalChapter {
|
- `lib/magazines.ts` → `/api/v1/magazines/*` — Magazines
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String
|
|
||||||
chapter Int
|
|
||||||
title String
|
|
||||||
type String
|
|
||||||
slug String
|
|
||||||
order Int
|
|
||||||
paragraphs String[]
|
|
||||||
|
|
||||||
@@unique([book, slug])
|
|
||||||
@@index([book])
|
|
||||||
@@map("journal_chapters")
|
|
||||||
}
|
|
||||||
|
|
||||||
model MagazineMeta {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String @unique
|
|
||||||
data Json
|
|
||||||
|
|
||||||
@@map("magazine_meta")
|
|
||||||
}
|
|
||||||
|
|
||||||
model MagazineIssue {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
book String
|
|
||||||
volume Int
|
|
||||||
part Int
|
|
||||||
title String
|
|
||||||
slug String
|
|
||||||
order Int
|
|
||||||
paragraphs String[]
|
|
||||||
paragraphsJson String? // JSON string fallback for large issues (BSON wire protocol workaround)
|
|
||||||
|
|
||||||
@@unique([book, slug])
|
|
||||||
@@index([book])
|
|
||||||
@@index([book, volume])
|
|
||||||
@@map("magazine_issues")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Letter {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
slug String @unique
|
|
||||||
recipients String[] // array of individual recipient names
|
|
||||||
recipientDisplay String // original combined string for display
|
|
||||||
date String?
|
|
||||||
dateRef String?
|
|
||||||
year Int?
|
|
||||||
month Int?
|
|
||||||
day Int?
|
|
||||||
location String?
|
|
||||||
salutation String?
|
|
||||||
paragraphs String[]
|
|
||||||
|
|
||||||
@@index([year])
|
|
||||||
@@index([recipients])
|
|
||||||
@@index([location])
|
|
||||||
@@index([year, month])
|
|
||||||
@@map("letters")
|
|
||||||
}
|
|
||||||
|
|
||||||
model GlossaryEntry {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
term String
|
|
||||||
definition String
|
|
||||||
definitionHtml String
|
|
||||||
|
|
||||||
@@unique([term])
|
|
||||||
@@map("glossary")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Disciple {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
initiatedName String
|
|
||||||
suffix String // "Dasa" | "Devi Dasi" | "Sw"
|
|
||||||
initiationDate DateTime? // 1st of the month (exact day unknown unless verified)
|
|
||||||
initiationPlace String?
|
|
||||||
karmiName String? // pre-initiation (birth) name
|
|
||||||
avatar String? // URL to profile photo
|
|
||||||
about String? // biographical notes
|
|
||||||
tags String[]
|
|
||||||
isVerified Boolean @default(false)
|
|
||||||
|
|
||||||
@@index([initiatedName])
|
|
||||||
@@index([initiationPlace])
|
|
||||||
@@index([initiationDate])
|
|
||||||
@@index([suffix])
|
|
||||||
@@index([tags])
|
|
||||||
@@map("disciples")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContentBlock {
|
|
||||||
text String
|
|
||||||
format String @default("paragraph")
|
|
||||||
alignment String @default("left")
|
|
||||||
speaker String?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Transcription {
|
|
||||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
||||||
slug String @unique
|
|
||||||
name String
|
|
||||||
type String // "lecture" | "conversation"
|
|
||||||
date String?
|
|
||||||
year Int?
|
|
||||||
month Int?
|
|
||||||
day Int?
|
|
||||||
place String?
|
|
||||||
context String?
|
|
||||||
reference String?
|
|
||||||
summary String?
|
|
||||||
content ContentBlock[]
|
|
||||||
tags String[]
|
|
||||||
participants String[]
|
|
||||||
language String @default("en")
|
|
||||||
source String?
|
|
||||||
durationMinutes Int?
|
|
||||||
audioUrl String?
|
|
||||||
isPublished Boolean @default(false)
|
|
||||||
notes String?
|
|
||||||
|
|
||||||
@@map("transcriptions")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -503,7 +318,7 @@ Seed script: `npx tsx scripts/seed-disciples.ts`
|
|||||||
**Schema notes**:
|
**Schema notes**:
|
||||||
- `recipients` is an array of individual names (e.g., `["Mukunda", "Janaki"]`)
|
- `recipients` is an array of individual names (e.g., `["Mukunda", "Janaki"]`)
|
||||||
- `recipientDisplay` is the original combined string (e.g., `"Mukunda, Janaki"`)
|
- `recipientDisplay` is the original combined string (e.g., `"Mukunda, Janaki"`)
|
||||||
- Searching for a recipient uses Prisma `{ has: name }` to match any letter where that person appears
|
- Searching for a recipient filters via the BFF endpoint (matches any letter where that person appears)
|
||||||
- Multi-recipient groups are split by `,`, `;`, ` and `, ` & `
|
- Multi-recipient groups are split by `,`, `;`, ` and `, ` & `
|
||||||
- Trailing punctuation (`:`, `,`, `.`) cleaned from names
|
- Trailing punctuation (`:`, `,`, `.`) cleaned from names
|
||||||
|
|
||||||
@@ -518,9 +333,7 @@ Seed script: `npx tsx scripts/seed-disciples.ts`
|
|||||||
- **Audio**: 99.1% have linked audio recordings from Cloudflare R2 (`audioUrl` field)
|
- **Audio**: 99.1% have linked audio recordings from Cloudflare R2 (`audioUrl` field)
|
||||||
- **Empty content**: 30 transcriptions (Hindi/Bengali lectures) have no English text but may have audio
|
- **Empty content**: 30 transcriptions (Hindi/Bengali lectures) have no English text but may have audio
|
||||||
|
|
||||||
Data layer: `lib/transcriptions.ts` (reads from Prisma/MongoDB, NOT local JSON files)
|
Data layer: `lib/transcriptions.ts` (calls BFF API, NOT local JSON files or direct MongoDB)
|
||||||
|
|
||||||
Seed script: `cd knowledgebase && npx tsx scripts/seed-transcriptions.ts`
|
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
@@ -771,7 +584,10 @@ SSR and DS have parent chapters with sub-chapters stored as individual `prose_ch
|
|||||||
A site-wide floating audio player for transcription recordings (and future music library). Built with framer-motion for animations.
|
A site-wide floating audio player for transcription recordings (and future music library). Built with framer-motion for animations.
|
||||||
|
|
||||||
- **Desktop**: Centered floating bar (max-width 680px) with cover image, track info, transport controls (prev/play/next), volume slider, source link, close button
|
- **Desktop**: Centered floating bar (max-width 680px) with cover image, track info, transport controls (prev/play/next), volume slider, source link, close button
|
||||||
- **Mobile**: Auto-minimizes to a floating pill (cover image with circular progress ring and audio wave animation) after 8 seconds of inactivity. Tap to expand. Full player shows two rows: track info row + centered transport controls
|
- **Mobile**: Full player shows two rows: track info row + centered transport controls
|
||||||
|
- **Auto-minimize**: After 8 seconds of inactivity on **both mobile and desktop**, the player auto-minimizes to a floating pill. The minimized pill shows cover image with a circular progress ring and audio wave animation. Tap/click to expand.
|
||||||
|
- **X button behavior**: Minimizes the player if audio is playing; stops playback entirely if audio is paused
|
||||||
|
- **Clicking outside the player**: Minimizes it (does not stop playback)
|
||||||
- **Z-index**: `z-40` — below text selection toolbar (z-80), drawers (z-90), modals (z-100)
|
- **Z-index**: `z-40` — below text selection toolbar (z-80), drawers (z-90), modals (z-100)
|
||||||
- **Hidden when selection toolbar is active** on mobile to avoid overlap
|
- **Hidden when selection toolbar is active** on mobile to avoid overlap
|
||||||
- **Forced dark surface** (`bg-[#1c1c1e]`) for accessibility contrast regardless of theme
|
- **Forced dark surface** (`bg-[#1c1c1e]`) for accessibility contrast regardless of theme
|
||||||
@@ -799,8 +615,9 @@ The `AudioPlayerProvider` wraps the entire app in `layout.tsx`. The `FloatingPla
|
|||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
```
|
```
|
||||||
DATABASE_URL=mongodb://user:pass@host:port/spsays?authSource=admin
|
BFF_URL=http://localhost:8080 # Go BFF API server URL (default: http://localhost:8080)
|
||||||
NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org
|
ALLOW_RTF=true # Enable RTF viewer (development only)
|
||||||
|
NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org # Public site URL for OG images
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -808,21 +625,20 @@ NEXT_PUBLIC_SITE_URL=https://prabhupadasays.org
|
|||||||
## How to Run
|
## How to Run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Development (from knowledgebase/)
|
# 1. Start the Go BFF server (required — all data comes from the BFF)
|
||||||
npm run dev
|
cd spsays-bff && go run cmd/api/main.go # Starts on :8080 by default
|
||||||
|
|
||||||
# Prisma
|
# 2. Development (from knowledgebase/)
|
||||||
npx prisma generate # Regenerate Prisma client after schema changes
|
npm run dev # Next.js dev server with Turbopack
|
||||||
|
|
||||||
# Build
|
# 3. Build
|
||||||
npx next build
|
npx next build
|
||||||
|
|
||||||
# Extraction & seeding scripts are in extractor/ — see extractor/scripts/
|
# Extraction & seeding scripts are in extractor/ — see extractor/scripts/
|
||||||
|
|
||||||
# BFF API server (from ../spsays-bff/)
|
|
||||||
make run # Build + start Go API on :8080
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Note**: No `npx prisma generate`, `npx prisma db push`, or MongoDB connection string needed in the frontend. The BFF server must be running for any page to load data.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Verse JSON Schema (BG/SB/CC/SB1962/ISO/NOI)
|
## Verse JSON Schema (BG/SB/CC/SB1962/ISO/NOI)
|
||||||
@@ -946,7 +762,7 @@ Content block formats: `"paragraph"` (body text), `"verse"` (centered italic), `
|
|||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
1. **MongoDB BSON wire corruption**: The MongoDB server occasionally corrupts large BSON documents. Workaround: seed using `insertOne` + `$push` for paragraphs one at a time.
|
1. **BFF dependency** — The knowledgebase requires the Go BFF server to be running; all pages will fail to load data if the BFF is down.
|
||||||
|
|
||||||
2. **SB verse numbering**: 5 duplicate verse reference tags in the HTML. Fixed by using the TEXT N header as authoritative.
|
2. **SB verse numbering**: 5 duplicate verse reference tags in the HTML. Fixed by using the TEXT N header as authoritative.
|
||||||
|
|
||||||
@@ -956,10 +772,8 @@ Content block formats: `"paragraph"` (body text), `"verse"` (centered italic), `
|
|||||||
|
|
||||||
5. **CSS zoom for font scaling**: `zoom` property works in Chrome/Safari/Edge but may not work in older Firefox (< 126). A `transform: scale()` fallback is provided via `@supports not (zoom: 1.1)`.
|
5. **CSS zoom for font scaling**: `zoom` property works in Chrome/Safari/Edge but may not work in older Firefox (< 126). A `transform: scale()` fallback is provided via `@supports not (zoom: 1.1)`.
|
||||||
|
|
||||||
6. **Password protection requires ACCESS_KEY at runtime**: The `PasswordGate` component checks the server at runtime via `/api/verify-access`. The env var must be available when the server is running, not just at build time.
|
6. **Transcription BSON fallback** — 1 document stores content as `contentJson` string due to BSON wire protocol limits; `getTranscription()` transparently parses it
|
||||||
|
|
||||||
7. **Transcription BSON fallback** — 1 document stores content as `contentJson` string due to BSON wire protocol limits; `getTranscription()` transparently parses it
|
7. **Empty transcriptions** — 30 entries have no English text content (Hindi/Bengali recordings); the UI shows "No transcription available" with the audio player still accessible
|
||||||
|
|
||||||
8. **Empty transcriptions** — 30 entries have no English text content (Hindi/Bengali recordings); the UI shows "No transcription available" with the audio player still accessible
|
8. **Audio player z-index** — Player is hidden when text selection toolbar is active on mobile to avoid overlap
|
||||||
|
|
||||||
9. **Audio player z-index** — Player is hidden when text selection toolbar is active on mobile to avoid overlap
|
|
||||||
Reference in New Issue
Block a user