diff --git a/packages/apps/backend/src/data-stores/OutputSettingsStore.ts b/packages/apps/backend/src/data-stores/OutputSettingsStore.ts
index 99949d0..a760606 100644
--- a/packages/apps/backend/src/data-stores/OutputSettingsStore.ts
+++ b/packages/apps/backend/src/data-stores/OutputSettingsStore.ts
@@ -7,7 +7,7 @@ export class OutputSettingsStore {
// _id: '',
// TODO: load these from persistent store upon startup?
- fontSize: 10,
+ fontSize: 7,
mirrorHorizontally: false,
mirrorVertically: false,
@@ -15,8 +15,8 @@ export class OutputSettingsStore {
focusPosition: 'center',
showFocusPosition: false,
- marginHorizontal: 5,
- marginVertical: 5,
+ marginHorizontal: 1,
+ marginVertical: 1,
activeRundownPlaylistId: null,
})
diff --git a/packages/apps/client/src/PrompterStyles.css b/packages/apps/client/src/PrompterStyles.css
index 79ea868..97a62f4 100644
--- a/packages/apps/client/src/PrompterStyles.css
+++ b/packages/apps/client/src/PrompterStyles.css
@@ -20,6 +20,14 @@
font-size: var(--prompter-font-size-base);
line-height: var(--prompter-line-height);
+
+ /* These are needed to maintain compatibility with Prose-mirror's text layout */
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ white-space: break-spaces;
+ -webkit-font-variant-ligatures: none;
+ font-variant-ligatures: none;
+ font-feature-settings: 'liga' 0;
}
.Prompter p {
diff --git a/packages/apps/client/src/components/CurrentRundown/CurrentRundown.tsx b/packages/apps/client/src/components/CurrentRundown/CurrentRundown.tsx
index be48e92..c2adbc2 100644
--- a/packages/apps/client/src/components/CurrentRundown/CurrentRundown.tsx
+++ b/packages/apps/client/src/components/CurrentRundown/CurrentRundown.tsx
@@ -37,9 +37,9 @@ const CurrentRundown = observer((): React.JSX.Element => {
-
+
{openRundown.segmentsInOrder.map((segment) => (
- -
+
-
))}
diff --git a/packages/apps/client/src/components/CurrentRundown/Segment.tsx b/packages/apps/client/src/components/CurrentRundown/Segment.tsx
index ca34aa7..9227f57 100644
--- a/packages/apps/client/src/components/CurrentRundown/Segment.tsx
+++ b/packages/apps/client/src/components/CurrentRundown/Segment.tsx
@@ -13,21 +13,25 @@ const Segment = observer(({ segment }: { segment: UISegment }): React.JSX.Elemen
return lineId === RootAppStore.uiStore.selectedLineId
}
- function onClick(e: React.MouseEvent) {
+ function onFocus(e: React.FocusEvent) {
const lineId = e.currentTarget.dataset['lineId'] as UILineId
RootAppStore.uiStore.setSelectedLineId(lineId)
}
return (
<>
- {segment.name}
+
+ {segment.name}
+
{segment.linesInOrder.map((line) => (
-
diff --git a/packages/apps/client/src/index.scss b/packages/apps/client/src/index.scss
index 36b41c3..c31612d 100644
--- a/packages/apps/client/src/index.scss
+++ b/packages/apps/client/src/index.scss
@@ -34,3 +34,13 @@ $theme-colors: (
--color-dark-1: #{$dark-1};
--color-dark-2: #{$dark-2};
}
+
+/* Remove outline for non-keyboard :focus */
+*:focus:not(:focus-visible) {
+ outline: none;
+}
+
+/* Optional: Customize .focus-visible */
+:focus-visible {
+ outline: $primary solid 2px;
+}
diff --git a/packages/apps/client/src/stores/RundownStore.ts b/packages/apps/client/src/stores/RundownStore.ts
index 67d4019..b96d00e 100644
--- a/packages/apps/client/src/stores/RundownStore.ts
+++ b/packages/apps/client/src/stores/RundownStore.ts
@@ -97,8 +97,7 @@ export class RundownStore {
sendRundownToOutput = (id: RundownPlaylistId) => {
if (!this.outputSettings) return
// TODO: This really shouldn't require the entire outputSettings object to be available first
- this.connection.outputSettings.update(null, {
- ...this.outputSettings,
+ this.connection.outputSettings.patch(null, {
activeRundownPlaylistId: id,
})
}
diff --git a/packages/apps/client/src/views/Output/Output.module.scss b/packages/apps/client/src/views/Output/Output.module.scss
new file mode 100644
index 0000000..b9a54f9
--- /dev/null
+++ b/packages/apps/client/src/views/Output/Output.module.scss
@@ -0,0 +1,8 @@
+.Output {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ overflow: auto;
+}
diff --git a/packages/apps/client/src/views/Output/Output.tsx b/packages/apps/client/src/views/Output/Output.tsx
index da4edcc..da13b4c 100644
--- a/packages/apps/client/src/views/Output/Output.tsx
+++ b/packages/apps/client/src/views/Output/Output.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useRef } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef } from 'react'
import { observer } from 'mobx-react-lite'
import { RootAppStore } from 'src/stores/RootAppStore.ts'
@@ -8,7 +8,10 @@ import { Helmet } from 'react-helmet-async'
import { getCurrentTime } from 'src/lib/getCurrentTime'
import { useQueryParam } from 'src/lib/useQueryParam'
+import classes from './Output.module.scss'
+
const Output = observer(function Output(): React.ReactElement {
+ const rootEl = useRef(null)
const speed = useRef(0)
const isPrimary = useQueryParam('primary') !== null
@@ -26,7 +29,7 @@ const Output = observer(function Output(): React.ReactElement {
// don't do this, it's just for testing:
const interval = setInterval(() => {
- window.scrollBy(0, speed.current)
+ rootEl.current?.scrollBy(0, speed.current)
}, 1000 / 60)
return () => {
@@ -139,11 +142,26 @@ const Output = observer(function Output(): React.ReactElement {
*/
+ const fontSize = RootAppStore.outputSettingsStore.outputSettings.fontSize
+ const scaleVertical = RootAppStore.outputSettingsStore.outputSettings.mirrorVertically ? '-1' : '1'
+ const scaleHorizontal = RootAppStore.outputSettingsStore.outputSettings.mirrorHorizontally ? '-1' : '1'
+
+ const styleVariables = useMemo(
+ () =>
+ ({
+ '--prompter-font-size-base': `${fontSize}vw`,
+ transform: `scale(${scaleHorizontal}, ${scaleVertical})`,
+ } as React.CSSProperties),
+ [fontSize, scaleVertical, scaleHorizontal]
+ )
+
+ const className = `Prompter ${classes.Output}`
+
if (!rundown) {
return (
<>
{GLOBAL_SETTINGS}
-
+
>
)
}
@@ -151,7 +169,7 @@ const Output = observer(function Output(): React.ReactElement {
return (
<>
{GLOBAL_SETTINGS}
-
+
{rundown.name}
{rundown.segmentsInOrder.map((segment) => (