diff --git a/components/settings/asr-settings.tsx b/components/settings/asr-settings.tsx index 5666db0e..8c01ab48 100644 --- a/components/settings/asr-settings.tsx +++ b/components/settings/asr-settings.tsx @@ -89,6 +89,9 @@ export function ASRSettings({ selectedProviderId }: ASRSettingsProps) { setIsRecording(true); } else { try { + if (!navigator.mediaDevices?.getUserMedia) { + throw new Error('mediaDevices API not available (requires HTTPS or localhost)'); + } const stream = await navigator.mediaDevices.getUserMedia({ audio: true, }); diff --git a/components/slide-renderer/components/element/LatexElement/BaseLatexElement.tsx b/components/slide-renderer/components/element/LatexElement/BaseLatexElement.tsx index a1a1c15b..2601e5ac 100644 --- a/components/slide-renderer/components/element/LatexElement/BaseLatexElement.tsx +++ b/components/slide-renderer/components/element/LatexElement/BaseLatexElement.tsx @@ -3,6 +3,15 @@ import { useRef, useState, useLayoutEffect } from 'react'; import type { PPTLatexElement } from '@/lib/types/slides'; +function getViewBoxDims(viewBox: [number, number] | string | undefined): [number, number] { + if (Array.isArray(viewBox)) return viewBox; + if (typeof viewBox === 'string') { + const parts = viewBox.trim().split(/\s+/).map(Number); + return parts.length >= 4 ? [parts[2], parts[3]] : parts.length >= 2 ? [parts[0], parts[1]] : [0, 0]; + } + return [0, 0]; +} + export interface BaseLatexElementProps { elementInfo: PPTLatexElement; } @@ -47,9 +56,12 @@ export function BaseLatexElement({ elementInfo }: BaseLatexElementProps) { className="transform-origin-[0_0] overflow-visible" > { + const [vbW, vbH] = getViewBoxDims(elementInfo.viewBox); + const sx = vbW > 0 ? elementInfo.width / vbW : 1; + const sy = vbH > 0 ? elementInfo.height / vbH : 1; + return `scale(${sx}, ${sy}) translate(0,0) matrix(1,0,0,1,0,0)`; + })()} > diff --git a/components/slide-renderer/components/element/LatexElement/index.tsx b/components/slide-renderer/components/element/LatexElement/index.tsx index 9709cda6..fe47c8f9 100644 --- a/components/slide-renderer/components/element/LatexElement/index.tsx +++ b/components/slide-renderer/components/element/LatexElement/index.tsx @@ -3,6 +3,15 @@ import { useRef, useState, useLayoutEffect } from 'react'; import type { PPTLatexElement } from '@/lib/types/slides'; +function getViewBoxDims(viewBox: [number, number] | string | undefined): [number, number] { + if (Array.isArray(viewBox)) return viewBox; + if (typeof viewBox === 'string') { + const parts = viewBox.trim().split(/\s+/).map(Number); + return parts.length >= 4 ? [parts[2], parts[3]] : parts.length >= 2 ? [parts[0], parts[1]] : [0, 0]; + } + return [0, 0]; +} + export { BaseLatexElement } from './BaseLatexElement'; export interface LatexElementProps { @@ -61,9 +70,12 @@ export function LatexElement({ elementInfo, selectElement }: LatexElementProps) className="transform-origin-[0_0]" > { + const [vbW, vbH] = getViewBoxDims(elementInfo.viewBox); + const sx = vbW > 0 ? elementInfo.width / vbW : 1; + const sy = vbH > 0 ? elementInfo.height / vbH : 1; + return `scale(${sx}, ${sy}) translate(0,0) matrix(1,0,0,1,0,0)`; + })()} > diff --git a/components/slide-renderer/components/element/ShapeElement/BaseShapeElement.tsx b/components/slide-renderer/components/element/ShapeElement/BaseShapeElement.tsx index 66cde759..4a11e514 100644 --- a/components/slide-renderer/components/element/ShapeElement/BaseShapeElement.tsx +++ b/components/slide-renderer/components/element/ShapeElement/BaseShapeElement.tsx @@ -8,6 +8,15 @@ import { useElementFill } from '../hooks/useElementFill'; import { GradientDefs } from './GradientDefs'; import { PatternDefs } from './PatternDefs'; +function getViewBoxDims(viewBox: [number, number] | string | undefined): [number, number] { + if (Array.isArray(viewBox)) return viewBox; + if (typeof viewBox === 'string') { + const parts = viewBox.trim().split(/\s+/).map(Number); + return parts.length >= 4 ? [parts[2], parts[3]] : parts.length >= 2 ? [parts[0], parts[1]] : [0, 0]; + } + return [0, 0]; +} + export interface BaseShapeElementProps { elementInfo: PPTShapeElement; } @@ -72,9 +81,12 @@ export function BaseShapeElement({ elementInfo }: BaseShapeElementProps) { )} { + const [vbW, vbH] = getViewBoxDims(elementInfo.viewBox); + const sx = vbW > 0 ? elementInfo.width / vbW : 1; + const sy = vbH > 0 ? elementInfo.height / vbH : 1; + return `scale(${sx}, ${sy}) translate(0,0) matrix(1,0,0,1,0,0)`; + })()} > = 4 ? [parts[2], parts[3]] : parts.length >= 2 ? [parts[0], parts[1]] : [0, 0]; + } + return [0, 0]; +} + export { BaseShapeElement } from './BaseShapeElement'; export interface ShapeElementProps { @@ -144,9 +153,12 @@ export function ShapeElement({ elementInfo, selectElement }: ShapeElementProps) )} { + const [vbW, vbH] = getViewBoxDims(elementInfo.viewBox); + const sx = vbW > 0 ? elementInfo.width / vbW : 1; + const sy = vbH > 0 ? elementInfo.height / vbH : 1; + return `scale(${sx}, ${sy}) translate(0,0) matrix(1,0,0,1,0,0)`; + })()} > { + const parts = String(el.viewBox).trim().split(/\s+/).map(Number); + return parts.length >= 4 ? [parts[2], parts[3]] : parts.length >= 2 ? [parts[0], parts[1]] : [0, 0]; + })(); const scale = { - x: el.width / el.viewBox[0], - y: el.height / el.viewBox[1], + x: vb[0] > 0 ? el.width / vb[0] : 1, + y: vb[1] > 0 ? el.height / vb[1] : 1, }; const points = formatPoints(toPoints(el.path), ratioPx2Inch, scale); diff --git a/lib/generation/scene-generator.ts b/lib/generation/scene-generator.ts index 1dc22937..cd65ad70 100644 --- a/lib/generation/scene-generator.ts +++ b/lib/generation/scene-generator.ts @@ -394,8 +394,8 @@ function fixElementDefaults( if (el.type === 'shape') { const shapeEl = el as Record; - if (!shapeEl.viewBox) { - shapeEl.viewBox = `0 0 ${el.width ?? 100} ${el.height ?? 100}`; + if (!shapeEl.viewBox || !Array.isArray(shapeEl.viewBox)) { + shapeEl.viewBox = [el.width ?? 100, el.height ?? 100]; } if (!shapeEl.path) { // Default to rectangle