Added transcript tool
This commit is contained in:
parent
df92d97bfa
commit
b9570e903e
|
@ -88,7 +88,7 @@ module.exports = {
|
||||||
"no-new-wrappers": "warn",
|
"no-new-wrappers": "warn",
|
||||||
"no-octal-escape": "warn",
|
"no-octal-escape": "warn",
|
||||||
"no-param-reassign": "warn",
|
"no-param-reassign": "warn",
|
||||||
"no-plusplus": "warn",
|
// "no-plusplus": "warn",
|
||||||
"no-proto": "warn",
|
"no-proto": "warn",
|
||||||
"no-restricted-exports": "warn",
|
"no-restricted-exports": "warn",
|
||||||
"no-restricted-globals": "warn",
|
"no-restricted-globals": "warn",
|
||||||
|
|
|
@ -35,6 +35,7 @@ interface Props extends AppStaticProps {
|
||||||
navTitle: string | null | undefined;
|
navTitle: string | null | undefined;
|
||||||
thumbnail?: UploadImageFragment;
|
thumbnail?: UploadImageFragment;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
contentPanelScroolbar?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SENSIBILITY_SWIPE = 1.1;
|
const SENSIBILITY_SWIPE = 1.1;
|
||||||
|
@ -52,6 +53,7 @@ export function AppLayout(props: Props): JSX.Element {
|
||||||
navTitle,
|
navTitle,
|
||||||
description,
|
description,
|
||||||
subPanelIcon = Icon.Tune,
|
subPanelIcon = Icon.Tune,
|
||||||
|
contentPanelScroolbar = true,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -280,7 +282,10 @@ export function AppLayout(props: Props): JSX.Element {
|
||||||
{/* Content panel */}
|
{/* Content panel */}
|
||||||
<div
|
<div
|
||||||
id={AnchorIds.ContentPanel}
|
id={AnchorIds.ContentPanel}
|
||||||
className={`texture-paper-dots overflow-y-scroll bg-light [grid-area:content]`}
|
className={cJoin(
|
||||||
|
"texture-paper-dots bg-light [grid-area:content]",
|
||||||
|
cIf(contentPanelScroolbar, "overflow-y-scroll")
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{isDefined(contentPanel) ? (
|
{isDefined(contentPanel) ? (
|
||||||
contentPanel
|
contentPanel
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { cJoin } from "helpers/className";
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
width?: ContentPanelWidthSizes;
|
width?: ContentPanelWidthSizes;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ContentPanelWidthSizes {
|
export enum ContentPanelWidthSizes {
|
||||||
|
@ -12,18 +13,19 @@ export enum ContentPanelWidthSizes {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ContentPanel(props: Props): JSX.Element {
|
export function ContentPanel(props: Props): JSX.Element {
|
||||||
const { width = ContentPanelWidthSizes.Default, children } = props;
|
const { width = ContentPanelWidthSizes.Default, children, className } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`grid h-full px-4 desktop:px-10`}>
|
<div className="grid h-full">
|
||||||
<main
|
<main
|
||||||
className={cJoin(
|
className={cJoin(
|
||||||
"justify-self-center pt-10 pb-20 desktop:pt-20 desktop:pb-32",
|
"justify-self-center px-4 pt-10 pb-20 desktop:px-10 desktop:pt-20 desktop:pb-32",
|
||||||
width === ContentPanelWidthSizes.Default
|
width === ContentPanelWidthSizes.Default
|
||||||
? "max-w-2xl"
|
? "max-w-2xl"
|
||||||
: width === ContentPanelWidthSizes.Large
|
: width === ContentPanelWidthSizes.Large
|
||||||
? "max-w-4xl"
|
? "max-w-4xl"
|
||||||
: "w-full"
|
: "w-full",
|
||||||
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -0,0 +1,421 @@
|
||||||
|
import { AppLayout } from "components/AppLayout";
|
||||||
|
import { Icon } from "components/Ico";
|
||||||
|
import { Button } from "components/Inputs/Button";
|
||||||
|
import { ButtonGroup } from "components/Inputs/ButtonGroup";
|
||||||
|
import {
|
||||||
|
ContentPanel,
|
||||||
|
ContentPanelWidthSizes,
|
||||||
|
} from "components/Panels/ContentPanel";
|
||||||
|
import { ToolTip } from "components/ToolTip";
|
||||||
|
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
|
||||||
|
import { GetStaticPropsContext } from "next";
|
||||||
|
import { useCallback, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
|
interface Props extends AppStaticProps {}
|
||||||
|
|
||||||
|
const SIZE_MULTIPLIER = 1000;
|
||||||
|
|
||||||
|
function replaceSelection(
|
||||||
|
text: string,
|
||||||
|
selectionStart: number,
|
||||||
|
selectionEnd: number,
|
||||||
|
newSelectedText: string
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
text.substring(0, selectionStart) +
|
||||||
|
newSelectedText +
|
||||||
|
text.substring(selectionEnd)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function swapChar(char: string, swaps: string[]): string {
|
||||||
|
for (let index = 0; index < swaps.length; index++) {
|
||||||
|
if (char === swaps[index]) {
|
||||||
|
console.log(
|
||||||
|
"found it",
|
||||||
|
char,
|
||||||
|
" returning",
|
||||||
|
swaps[(index + 1) % swaps.length]
|
||||||
|
);
|
||||||
|
return swaps[(index + 1) % swaps.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return char;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Transcript(props: Props): JSX.Element {
|
||||||
|
const [text, setText] = useState("");
|
||||||
|
const [fontSize, setFontSize] = useState(1);
|
||||||
|
const [xOffset, setXOffset] = useState(0);
|
||||||
|
const [lineIndex, setLineIndex] = useState(0);
|
||||||
|
|
||||||
|
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
||||||
|
const updateDisplayedText = useCallback(() => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
setText(textAreaRef.current.value);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const updateLineIndex = useCallback(() => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
const subText = textAreaRef.current.value.substring(
|
||||||
|
0,
|
||||||
|
textAreaRef.current.selectionStart
|
||||||
|
);
|
||||||
|
setLineIndex(subText.split("\n").length - 1);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const convertPunctuation = useCallback(() => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
textAreaRef.current.value = textAreaRef.current.value
|
||||||
|
.replaceAll("...", "⋯")
|
||||||
|
.replaceAll("…", "⋯")
|
||||||
|
.replaceAll(":::", "⋯⋯")
|
||||||
|
.replaceAll(".", "。")
|
||||||
|
.replaceAll(",", "、")
|
||||||
|
.replaceAll("?", "?")
|
||||||
|
.replaceAll("!", "!");
|
||||||
|
updateDisplayedText();
|
||||||
|
}
|
||||||
|
}, [updateDisplayedText]);
|
||||||
|
|
||||||
|
const toggleDakuten = useCallback(() => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
const selectionStart = Math.min(
|
||||||
|
textAreaRef.current.selectionStart,
|
||||||
|
textAreaRef.current.selectionEnd
|
||||||
|
);
|
||||||
|
const selectionEnd = Math.max(
|
||||||
|
textAreaRef.current.selectionStart,
|
||||||
|
textAreaRef.current.selectionEnd
|
||||||
|
);
|
||||||
|
const selection = textAreaRef.current.value.substring(
|
||||||
|
selectionStart,
|
||||||
|
selectionEnd
|
||||||
|
);
|
||||||
|
if (selection.length === 1) {
|
||||||
|
let newSelection = selection;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hiragana
|
||||||
|
* a
|
||||||
|
*/
|
||||||
|
newSelection = swapChar(newSelection, ["か", "が"]);
|
||||||
|
newSelection = swapChar(newSelection, ["さ", "ざ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["た", "だ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["は", "ば", "ぱ"]);
|
||||||
|
// i
|
||||||
|
newSelection = swapChar(newSelection, ["き", "ぎ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["し", "じ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ち", "ぢ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ひ", "び", "ぴ"]);
|
||||||
|
// u
|
||||||
|
newSelection = swapChar(newSelection, ["く", "ぐ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["す", "ず"]);
|
||||||
|
newSelection = swapChar(newSelection, ["つ", "づ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ふ", "ぶ", "ぷ"]);
|
||||||
|
// e
|
||||||
|
newSelection = swapChar(newSelection, ["け", "げ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["せ", "ぜ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["て", "で"]);
|
||||||
|
newSelection = swapChar(newSelection, ["へ", "べ", "ぺ"]);
|
||||||
|
// o
|
||||||
|
newSelection = swapChar(newSelection, ["こ", "ご"]);
|
||||||
|
newSelection = swapChar(newSelection, ["そ", "ぞ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["と", "ど"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ほ", "ぼ", "ぽ"]);
|
||||||
|
// others
|
||||||
|
newSelection = swapChar(newSelection, ["う", "ゔ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ゝ", "ゞ"]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Katakana
|
||||||
|
* a
|
||||||
|
*/
|
||||||
|
newSelection = swapChar(newSelection, ["カ", "ガ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["サ", "ザ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["タ", "ダ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ハ", "バ", "パ"]);
|
||||||
|
// i
|
||||||
|
newSelection = swapChar(newSelection, ["キ", "ギ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["シ", "ジ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["チ", "ヂ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ヒ", "ビ", "ピ"]);
|
||||||
|
// u
|
||||||
|
newSelection = swapChar(newSelection, ["ク", "グ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ス", "ズ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ツ", "ヅ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["フ", "ブ", "プ"]);
|
||||||
|
// e
|
||||||
|
newSelection = swapChar(newSelection, ["ケ", "ゲ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["セ", "ゼ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["テ", "デ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ヘ", "ベ", "ペ"]);
|
||||||
|
// o
|
||||||
|
newSelection = swapChar(newSelection, ["コ", "ゴ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ソ", "ゾ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ト", "ド"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ホ", "ボ", "ポ"]);
|
||||||
|
// others
|
||||||
|
newSelection = swapChar(newSelection, ["ゥ", "ヴ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ヽ", "ヾ"]);
|
||||||
|
|
||||||
|
if (newSelection !== selection) {
|
||||||
|
textAreaRef.current.value = replaceSelection(
|
||||||
|
textAreaRef.current.value,
|
||||||
|
selectionStart,
|
||||||
|
selectionEnd,
|
||||||
|
newSelection
|
||||||
|
);
|
||||||
|
|
||||||
|
textAreaRef.current.selectionStart = selectionStart;
|
||||||
|
textAreaRef.current.selectionEnd = selectionEnd;
|
||||||
|
textAreaRef.current.focus();
|
||||||
|
|
||||||
|
updateDisplayedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [updateDisplayedText]);
|
||||||
|
|
||||||
|
const toggleSmallForm = useCallback(() => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
const selectionStart = Math.min(
|
||||||
|
textAreaRef.current.selectionStart,
|
||||||
|
textAreaRef.current.selectionEnd
|
||||||
|
);
|
||||||
|
const selectionEnd = Math.max(
|
||||||
|
textAreaRef.current.selectionStart,
|
||||||
|
textAreaRef.current.selectionEnd
|
||||||
|
);
|
||||||
|
const selection = textAreaRef.current.value.substring(
|
||||||
|
selectionStart,
|
||||||
|
selectionEnd
|
||||||
|
);
|
||||||
|
if (selection.length === 1) {
|
||||||
|
let newSelection = selection;
|
||||||
|
|
||||||
|
// Hiragana
|
||||||
|
newSelection = swapChar(newSelection, ["あ", "ぁ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["い", "ぃ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["う", "ぅ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["え", "ぇ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["お", "ぉ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["か", "ゕ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["け", "ゖ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["つ", "っ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["や", "ゃ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ゆ", "ゅ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["よ", "ょ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["わ", "ゎ"]);
|
||||||
|
// Katakana
|
||||||
|
newSelection = swapChar(newSelection, ["ア", "ァ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["イ", "ィ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ウ", "ゥ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["エ", "ェ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["オ", "ォ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ツ", "ッ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ヤ", "ャ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ユ", "ュ"]);
|
||||||
|
newSelection = swapChar(newSelection, ["ヨ", "ョ"]);
|
||||||
|
|
||||||
|
if (newSelection !== selection) {
|
||||||
|
textAreaRef.current.value = replaceSelection(
|
||||||
|
textAreaRef.current.value,
|
||||||
|
selectionStart,
|
||||||
|
selectionEnd,
|
||||||
|
newSelection
|
||||||
|
);
|
||||||
|
|
||||||
|
textAreaRef.current.selectionStart = selectionStart;
|
||||||
|
textAreaRef.current.selectionEnd = selectionEnd;
|
||||||
|
textAreaRef.current.focus();
|
||||||
|
|
||||||
|
updateDisplayedText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [updateDisplayedText]);
|
||||||
|
|
||||||
|
const insert = useCallback(
|
||||||
|
(insertedText: string) => {
|
||||||
|
if (textAreaRef.current) {
|
||||||
|
const selectionEnd = Math.max(
|
||||||
|
textAreaRef.current.selectionStart,
|
||||||
|
textAreaRef.current.selectionEnd
|
||||||
|
);
|
||||||
|
textAreaRef.current.value = replaceSelection(
|
||||||
|
textAreaRef.current.value,
|
||||||
|
selectionEnd,
|
||||||
|
selectionEnd,
|
||||||
|
insertedText
|
||||||
|
);
|
||||||
|
|
||||||
|
textAreaRef.current.selectionStart = selectionEnd;
|
||||||
|
textAreaRef.current.selectionEnd = selectionEnd + insertedText.length;
|
||||||
|
textAreaRef.current.focus();
|
||||||
|
|
||||||
|
updateDisplayedText();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[updateDisplayedText]
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<ContentPanel
|
||||||
|
width={ContentPanelWidthSizes.Full}
|
||||||
|
className="overflow-hidden !pr-0 !pt-4"
|
||||||
|
>
|
||||||
|
<div className="grid grid-flow-col grid-cols-[1fr_5rem]">
|
||||||
|
<textarea
|
||||||
|
ref={textAreaRef}
|
||||||
|
onChange={updateDisplayedText}
|
||||||
|
onClick={updateLineIndex}
|
||||||
|
onKeyUp={updateLineIndex}
|
||||||
|
title="Input textarea"
|
||||||
|
className="whitespace-pre"
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<p
|
||||||
|
className="h-[80vh] whitespace-nowrap font-[initial] font-bold
|
||||||
|
[writing-mode:vertical-rl] [transform-origin:top_right]"
|
||||||
|
style={{
|
||||||
|
transform: `scale(${fontSize}) translateX(${
|
||||||
|
fontSize * xOffset
|
||||||
|
}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text.split("\n")[lineIndex]}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap place-items-center gap-4 pr-24">
|
||||||
|
<div className="grid place-items-center">
|
||||||
|
<p>Text offset: {xOffset}px</p>
|
||||||
|
<input
|
||||||
|
title="Font size multiplier"
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
value={xOffset * 10}
|
||||||
|
onChange={(event) =>
|
||||||
|
setXOffset(parseInt(event.target.value, 10) / 10)
|
||||||
|
}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid place-items-center">
|
||||||
|
<p>Font size: {fontSize}x</p>
|
||||||
|
<input
|
||||||
|
title="Font size multiplier"
|
||||||
|
type="range"
|
||||||
|
min="1000"
|
||||||
|
max="3000"
|
||||||
|
value={fontSize * SIZE_MULTIPLIER}
|
||||||
|
onChange={(event) =>
|
||||||
|
setFontSize(parseInt(event.target.value, 10) / SIZE_MULTIPLIER)
|
||||||
|
}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
<ToolTip content="Automatically convert punctuations">
|
||||||
|
<Button icon={Icon.QuestionMark} onClick={convertPunctuation} />
|
||||||
|
</ToolTip>
|
||||||
|
<Button text={"か ⟺ が"} onClick={toggleDakuten} />
|
||||||
|
<Button text={"つ ⟺ っ"} onClick={toggleSmallForm} />
|
||||||
|
<Button text={"。"} onClick={() => insert("。")} />
|
||||||
|
<Button text={"?"} onClick={() => insert("?")} />
|
||||||
|
<Button text={"!"} onClick={() => insert("!")} />
|
||||||
|
<ToolTip
|
||||||
|
content={
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "「", onClick: () => insert("「") },
|
||||||
|
{ text: "」", onClick: () => insert("」") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "『", onClick: () => insert("『") },
|
||||||
|
{ text: "』", onClick: () => insert("』") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "【", onClick: () => insert("【") },
|
||||||
|
{ text: "】", onClick: () => insert("】") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "(", onClick: () => insert("(") },
|
||||||
|
{ text: ")", onClick: () => insert(")") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "〝", onClick: () => insert("〝") },
|
||||||
|
{ text: "〟", onClick: () => insert("〟") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "〈", onClick: () => insert("〈") },
|
||||||
|
{ text: "〉", onClick: () => insert("〉") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ButtonGroup
|
||||||
|
buttonsProps={[
|
||||||
|
{ text: "《", onClick: () => insert("《") },
|
||||||
|
{ text: "》", onClick: () => insert("》") },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button text={"Quotations"} />
|
||||||
|
</ToolTip>
|
||||||
|
|
||||||
|
<Button text={"⋯"} onClick={() => insert("⋯")} />
|
||||||
|
<Button text={"※"} onClick={() => insert("※")} />
|
||||||
|
<Button text={'" "'} onClick={() => insert(" ")} />
|
||||||
|
</div>
|
||||||
|
</ContentPanel>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
convertPunctuation,
|
||||||
|
fontSize,
|
||||||
|
insert,
|
||||||
|
lineIndex,
|
||||||
|
text,
|
||||||
|
toggleDakuten,
|
||||||
|
toggleSmallForm,
|
||||||
|
updateDisplayedText,
|
||||||
|
updateLineIndex,
|
||||||
|
xOffset,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppLayout
|
||||||
|
navTitle="Transcript"
|
||||||
|
contentPanel={contentPanel}
|
||||||
|
{...props}
|
||||||
|
contentPanelScroolbar={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps(
|
||||||
|
context: GetStaticPropsContext
|
||||||
|
): Promise<{ notFound: boolean } | { props: Props }> {
|
||||||
|
const props: Props = {
|
||||||
|
...(await getAppStaticProps(context)),
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: props,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue