diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 5bdc6a75..9d3923f4 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -6,6 +6,10 @@ services: dockerfile: Dockerfile args: VITE_PROXY_SERVER: ${JUMBLE_PROXY_SERVER_URL:-http://localhost:8090} + # Same-origin paths; reverse-proxy in front of :8089 should forward /api/* (see PROXY_SETUP.md). + VITE_READ_ALOUD_TTS_URL: ${JUMBLE_READ_ALOUD_TTS_URL:-/api/piper-tts} + VITE_LANGUAGE_TOOL_URL: ${JUMBLE_LANGUAGE_TOOL_URL:-/api/languagetool} + VITE_TRANSLATE_URL: ${JUMBLE_TRANSLATE_URL:-/api/translate} ports: - "8089:80" restart: unless-stopped diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 64877235..57312b7f 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -10,7 +10,7 @@ # ProxyPassReverse /api/piper-tts http://127.0.0.1:9876/api/piper-tts # ProxyPass / http://127.0.0.1:8089/ # so the browser hits same-origin /api/piper-tts → piper HTTP proxy (see services/piper-tts-proxy + PROXY_SETUP.md); /sites/ → OG proxy; else static SPA on 8089. -# VITE_PROXY_SERVER / VITE_READ_ALOUD_TTS_URL are baked at image build — see scripts/build-and-push-prod.sh +# VITE_PROXY_SERVER, VITE_READ_ALOUD_TTS_URL, VITE_LANGUAGE_TOOL_URL, VITE_TRANSLATE_URL are baked at image build — see scripts/build-and-push-prod.sh (docker compose here does not build the SPA). # # NIP-66 monitor: set NIP66_MONITOR_NSEC (and optionally NIP66_MONITOR_NPUB) in the host env or .env. # - Cron service `jumble-nip66-monitor` (Imwald NIP-66 monitor image) uses NIP66_MONITOR_NSEC to publish 30166/10166; nsec never goes to the client. diff --git a/docker-compose.yml b/docker-compose.yml index ccfcd070..5ca2d3eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,10 @@ services: dockerfile: Dockerfile args: VITE_PROXY_SERVER: ${JUMBLE_PROXY_SERVER_URL:-http://localhost:8090} + # Same-origin paths; reverse-proxy in front of :8089 should forward /api/* (see PROXY_SETUP.md). + VITE_READ_ALOUD_TTS_URL: ${JUMBLE_READ_ALOUD_TTS_URL:-/api/piper-tts} + VITE_LANGUAGE_TOOL_URL: ${JUMBLE_LANGUAGE_TOOL_URL:-/api/languagetool} + VITE_TRANSLATE_URL: ${JUMBLE_TRANSLATE_URL:-/api/translate} ports: - "8089:80" restart: unless-stopped diff --git a/src/components/AdvancedEventLab/AdvancedEventLabDialog.tsx b/src/components/AdvancedEventLab/AdvancedEventLabDialog.tsx index 909e88b3..bdc532ed 100644 --- a/src/components/AdvancedEventLab/AdvancedEventLabDialog.tsx +++ b/src/components/AdvancedEventLab/AdvancedEventLabDialog.tsx @@ -8,6 +8,7 @@ import { DialogTitle } from '@/components/ui/dialog' import { Label } from '@/components/ui/label' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Select, SelectContent, @@ -245,6 +246,7 @@ export default function AdvancedEventLabDialog({ const LAB_DRAFT_DEBOUNCE_MS = 500 const [previewDoc, setPreviewDoc] = useState('') + const [labBodyTab, setLabBodyTab] = useState<'edit' | 'preview'>('edit') /** Stable while payload matches; avoids remounting the editor when the parent passes a new `initial` object reference. */ const labEditorMountFingerprint = @@ -276,6 +278,15 @@ export default function AdvancedEventLabDialog({ }, PREVIEW_DEBOUNCE_MS) }, []) + const flushPreviewDocNow = useCallback(() => { + if (previewDebounceTimerRef.current) { + clearTimeout(previewDebounceTimerRef.current) + previewDebounceTimerRef.current = null + } + const doc = markupView.current?.state.doc.toString() ?? sliceRef.current?.content ?? '' + setPreviewDoc(doc) + }, []) + useEffect(() => { schedulePreviewUpdateRef.current = schedulePreviewUpdate }, [schedulePreviewUpdate]) @@ -340,6 +351,8 @@ export default function AdvancedEventLabDialog({ previewDebounceTimerRef.current = null } setPreviewDoc('') + } else { + setLabBodyTab('edit') } }, [open]) @@ -1019,28 +1032,46 @@ export default function AdvancedEventLabDialog({ -
- - -
-
-

+
+ { + const next = v as 'edit' | 'preview' + if (next === 'preview') flushPreviewDocNow() + setLabBodyTab(next) + }} + className="flex min-h-0 flex-1 flex-col gap-2" + > + + {t( markupMode === 'asciidoc' ? 'Advanced lab markup label asciidoc' : 'Advanced lab markup label markdown' )} -

+ + + {t('Advanced lab preview')} + + + + +
-
-
-

- {t('Advanced lab preview')} -

-
+ + + +
-
-
+
+
{formatToolbar ? ( diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx index 72ead4b8..ab9e1e3a 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/src/components/ui/dropdown-menu.tsx @@ -143,14 +143,17 @@ const DropdownMenuSubContent = React.forwardRef<
{props.children}
{showScrollButtons && canScrollDown && ( -
+