Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Commit 242616b

Browse files
committed
feat(Output/Editor): try and match prompter font size in the editor
1 parent 8e0c03e commit 242616b

File tree

5 files changed

+110
-8
lines changed

5 files changed

+110
-8
lines changed

packages/apps/client/src/PrompterStyles.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
-webkit-font-variant-ligatures: none;
2929
font-variant-ligatures: none;
3030
font-feature-settings: 'liga' 0;
31+
font-kerning: none;
3132
}
3233

3334
.Prompter p {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.ScriptEditor {
2+
container-type: inline-size;
3+
}
Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,70 @@
1-
import React from 'react'
1+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
22
import { Editor } from './Editor'
33

44
import 'src/PrompterStyles.css'
5+
import classes from './ScriptEditor.module.scss'
6+
import { observer } from 'mobx-react-lite'
7+
import { RootAppStore } from 'src/stores/RootAppStore'
8+
import { useDebouncedCallback } from 'src/lib/lib'
9+
10+
export const ScriptEditor = observer(function ScriptEditor(): React.JSX.Element {
11+
const [fontSize, setFontSize] = useState(10)
12+
const [width, setWidth] = useState<number | null>(null)
13+
14+
const rootEl = useRef<HTMLDivElement>(null)
15+
16+
useEffect(() => {
17+
RootAppStore.outputSettingsStore.initialize()
18+
}, [])
19+
20+
const viewportFontSize = RootAppStore.outputSettingsStore.outputSettings.fontSize
21+
22+
useEffect(() => {
23+
if (width === null) return
24+
25+
setFontSize((width * viewportFontSize) / 100)
26+
}, [viewportFontSize, width])
27+
28+
const dividerSplitPosition = RootAppStore.uiStore.viewDividerPosition
29+
30+
const onResize = useDebouncedCallback(
31+
function onResize() {
32+
if (!rootEl.current) return
33+
const { width: elementWidth } = rootEl.current.getBoundingClientRect()
34+
35+
setWidth(elementWidth)
36+
},
37+
[],
38+
{
39+
delay: 100,
40+
}
41+
)
42+
43+
useLayoutEffect(() => {
44+
void dividerSplitPosition
45+
onResize()
46+
}, [dividerSplitPosition, onResize])
47+
48+
useEffect(() => {
49+
window.addEventListener('resize', onResize)
50+
51+
return () => {
52+
window.removeEventListener('resize', onResize)
53+
}
54+
}, [onResize])
55+
56+
const style = useMemo(
57+
() =>
58+
({
59+
'--prompter-font-size-base': `${fontSize}px`,
60+
} as React.CSSProperties),
61+
[fontSize]
62+
)
563

6-
export function ScriptEditor(): React.JSX.Element {
764
return (
8-
<>
9-
<Editor className="bg-black Prompter" />
10-
</>
65+
<div className={`bg-black Prompter ${classes.ScriptEditor}`} style={style} ref={rootEl}>
66+
<Editor />
67+
</div>
1168
)
12-
}
69+
})
70+
ScriptEditor.displayName = 'ScriptEditor'

packages/apps/client/src/lib/lib.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
1+
import React, { useCallback, useEffect, useRef } from 'react'
12
import { v4 } from 'uuid'
23

34
export function randomId() {
45
return v4()
56
}
7+
8+
export function useMergedRefs<T>(...refs: React.Ref<T>[]): React.RefCallback<T> {
9+
return useCallback((node) => {
10+
for (const ref of refs) {
11+
if (ref === null) continue
12+
if (typeof ref === 'function') {
13+
ref(node)
14+
continue
15+
}
16+
//@ts-expect-error React's typings prohibit writing to the ref, but it's actually OK
17+
ref.current = node
18+
}
19+
// eslint-disable-next-line react-hooks/exhaustive-deps
20+
}, refs)
21+
}
22+
23+
export function useDebouncedCallback(clb: () => void, deps: React.DependencyList, opts: { delay: number }) {
24+
const debounce = useRef<number | null>(null)
25+
26+
useEffect(() => {
27+
return () => {
28+
if (debounce.current) window.clearTimeout(debounce.current)
29+
}
30+
}, [])
31+
32+
return useCallback(() => {
33+
if (debounce.current) window.clearTimeout(debounce.current)
34+
35+
debounce.current = window.setTimeout(() => {
36+
debounce.current = null
37+
clb()
38+
}, opts.delay)
39+
// eslint-disable-next-line react-hooks/exhaustive-deps
40+
}, deps)
41+
}

packages/apps/client/src/views/RundownScript/RundownScript.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from 'react'
1+
import { ChangeEvent, useEffect, useRef } from 'react'
22
import { observer } from 'mobx-react-lite'
33
import classes from './RundownScript.module.scss'
44
import { CurrentRundown } from 'src/components/CurrentRundown/CurrentRundown'
@@ -20,6 +20,10 @@ const RundownScript = observer((): React.JSX.Element => {
2020
RootAppStore.rundownStore.loadRundown(playlistId)
2121
}, [playlistId])
2222

23+
function onChange(e: { value: number }) {
24+
RootAppStore.uiStore.setViewDividerPosition(e.value)
25+
}
26+
2327
return (
2428
<>
2529
<Helmet>
@@ -28,7 +32,7 @@ const RundownScript = observer((): React.JSX.Element => {
2832
</Helmet>
2933
<SplitPanel
3034
position={RootAppStore.uiStore.viewDividerPosition}
31-
onChange={(e) => RootAppStore.uiStore.setViewDividerPosition(e.value)}
35+
onChange={onChange}
3236
className={classes.RundownScript}
3337
childrenBegin={<CurrentRundown />}
3438
childrenEnd={<ScriptEditor />}

0 commit comments

Comments
 (0)