diff --git a/README.md b/README.md index ee9a14d..d0b8e10 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,47 @@ # codex-documentation -This is a Next.js application generated with -[Create Fumadocs](https://github.com/fuma-nama/fumadocs). +User-facing documentation for Codex Editor, built with Next.js and Fumadocs. -Run development server: +## Purpose + +This site explains how translators, project coordinators, media teams, and support staff use the current Codex desktop app and Codex Translation Editor extension. Treat `codex-editor` and `codex` as source-of-truth repos for product behavior and UI labels. + +## Local Development ```bash -npm run dev -# or +pnpm install pnpm dev -# or -yarn dev ``` -Open http://localhost:3000 with your browser to see the result. - -## Explore - -In the project, you can see: +Open http://localhost:3000. -- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content. -- `app/layout.config.tsx`: Shared options for layouts, optional but preferred to keep. +After adding, deleting, or renaming MDX files, regenerate the Fumadocs source layer: -| Route | Description | -| ------------------------- | ------------------------------------------------------ | -| `app/(home)` | The route group for your landing page and other pages. | -| `app/docs` | The documentation layout and pages. | -| `app/api/search/route.ts` | The Route Handler for search. | +```bash +pnpm postinstall +``` -### Fumadocs MDX +## Useful Commands -A `source.config.ts` config file has been included, you can customise different options like frontmatter schema. +```bash +pnpm build +pnpm watch +``` -Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details. +## Content Map -## Learn More +- `content/docs/` contains MDX documentation pages. +- `content/docs/meta.json` controls top-level navigation. +- Each section folder has its own `meta.json` for ordering. +- `public/images/` contains screenshots and static assets. +- `components/` contains custom MDX components such as troubleshooting flows. +- `docs/plans/` contains durable branch briefs for larger rewrites. -To learn more about Next.js and Fumadocs, take a look at the following -resources: +## Writing Rules -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js - features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -- [Fumadocs](https://fumadocs.vercel.app) - learn about Fumadocs +- Use current Codex UI labels exactly. +- Prefer task-based pages over long feature inventories. +- Keep FAQ answers short and link to canonical pages. +- Use "cell" or "segment" for general workflows; use "verse" only for scripture-specific guidance. +- Do not document inactive importers or unshipped features as available. +- When app behavior is involved, distinguish the Codex desktop app from the Codex Translation Editor extension. diff --git a/components/loom-video.tsx b/components/loom-video.tsx deleted file mode 100644 index f79b244..0000000 --- a/components/loom-video.tsx +++ /dev/null @@ -1,126 +0,0 @@ -"use client"; - -import { useCallback, useEffect, useRef } from 'react'; - -interface LoomVideoProps { - videoId: string; - timestamp?: number; - title?: string; - className?: string; -} - -export function LoomVideo({ videoId, timestamp = 0, title = "Loom Video", className = "" }: LoomVideoProps) { - const containerRef = useRef(null); - const embedUrl = `https://www.loom.com/embed/${videoId}?sid=1&t=${timestamp}`; - - const replaceWithPlaceholder = useCallback((container: HTMLDivElement, iframe: HTMLIFrameElement) => { - // Store the iframe data for restoration - container.setAttribute('data-iframe-src', iframe.src); - container.setAttribute('data-iframe-title', iframe.title || ''); - container.setAttribute('data-is-placeholder', 'true'); - - // Create placeholder content - const placeholder = document.createElement('div'); - placeholder.className = 'absolute inset-0 bg-gray-900 flex flex-col items-center justify-center cursor-pointer group transition-all hover:bg-gray-800'; - placeholder.innerHTML = ` -
- - - -
-

${iframe.title || 'Click to play video'}

- `; - - // Replace iframe with a clickable placeholder. - iframe.remove(); - container.appendChild(placeholder); - }, []); - - const restoreIframe = useCallback((container: HTMLDivElement) => { - const src = container.getAttribute('data-iframe-src'); - const title = container.getAttribute('data-iframe-title'); - - if (src) { - // Remove placeholder - const placeholder = container.querySelector('div'); - if (placeholder) { - placeholder.remove(); - } - - // Create new iframe - const iframe = document.createElement('iframe'); - iframe.src = src; - iframe.title = title || ''; - iframe.frameBorder = '0'; - iframe.allowFullscreen = true; - iframe.className = 'absolute inset-0 w-full h-full'; - iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; - - // Add iframe to container - container.appendChild(iframe); - - // Remove placeholder attributes - container.removeAttribute('data-iframe-src'); - container.removeAttribute('data-iframe-title'); - container.removeAttribute('data-is-placeholder'); - } - }, []); - - const pauseOtherVideos = useCallback((activeContainer: HTMLDivElement) => { - // Find all other video containers and replace them with placeholders - const allVideoContainers = document.querySelectorAll('[data-loom-video]'); - - allVideoContainers.forEach((container) => { - if (container !== activeContainer && !container.hasAttribute('data-is-placeholder')) { - const iframe = container.querySelector('iframe'); - if (iframe) { - replaceWithPlaceholder(container as HTMLDivElement, iframe); - } - } - }); - }, [replaceWithPlaceholder]); - - const ensureVideoActive = useCallback((container: HTMLDivElement) => { - // If this container is a placeholder, restore the iframe - if (container.hasAttribute('data-is-placeholder')) { - restoreIframe(container); - } - }, [restoreIframe]); - - useEffect(() => { - const container = containerRef.current; - if (!container) return; - - const handleVideoClick = (event: Event) => { - const clickedContainer = (event.target as Element).closest('[data-loom-video]'); - if (clickedContainer === container) { - pauseOtherVideos(container); - ensureVideoActive(container); - } - }; - - document.addEventListener('click', handleVideoClick); - - return () => { - document.removeEventListener('click', handleVideoClick); - }; - }, [ensureVideoActive, pauseOtherVideos]); - - return ( -
-