Skip to content

Commit

Permalink
Screenshot Mode
Browse files Browse the repository at this point in the history
  • Loading branch information
graphemecluster committed Aug 31, 2024
1 parent 135d611 commit 8ac5849
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 30 deletions.
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ <h1 class="max-sm:col-span-2">香港圍頭話及客家話文字轉語音</h1>
<h2 class="group-hover:text-slate-700 group-hover:text-opacity-90 transition-[color]">香港<span class="text-[#d80818] group-hover:text-[#900612] group-hover:text-opacity-90 transition-[color]">本土語言</span>保育協會</h2>
</a>
</div>
<button id="btn-show" type="button" class="btn btn-ghost gap-1.5 hover:bg-opacity-10 max-sm:text-xl max-sm:font-normal max-sm:relative max-sm:left-4 sm:btn-lg sm:text-1.5xl sm:text-slate-500 sm:col-start-3 sm:row-start-1 sm:row-end-3">
<span class="icon-info"></span>關於
<button id="btn-show" type="button" class="btn btn-ghost gap-1.5 font-[650] hover:bg-opacity-10 max-sm:text-xl max-sm:font-normal max-sm:relative max-sm:left-4 sm:btn-lg sm:text-1.5xl sm:text-slate-500 sm:col-start-3 sm:row-start-1 sm:row-end-3">
<span class="icon-info mt-0.5"></span>關於
</button>
</header>
<main id="root"></main>
Expand All @@ -70,7 +70,7 @@ <h2 class="group-hover:text-slate-700 group-hover:text-opacity-90 transition-[co
<form method="dialog">
<button type="submit" class="btn btn-ghost w-14 h-14 min-h-14 text-4.5xl absolute right-3 top-3 text-slate-500 hover:bg-opacity-10" aria-label="關閉"><span class="icon-close"></span></button>
</form>
<h3 class="flex items-center gap-2 mx-6 mt-6 mb-4.5"><span class="icon-info"></span>關於</h3>
<h3 class="flex items-center gap-2 mx-6 mt-5.5 mb-5"><span class="icon-info mt-1"></span>關於</h3>
<hr />
<div class="flex-1 overflow-x-hidden overflow-y-auto">
<p>歡迎使用<b>香港圍頭話及客家話文字轉語音(Text-to-Speech)</b>朗讀器!</p>
Expand Down
40 changes: 27 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ import type { SettingsDialogPage, Sentence } from "./types";

export default function App() {
const queryOptions = useQueryOptions();
const { language, voice, inferenceMode, voiceSpeed, hakkaToneMode, setLanguage, setVoice } = queryOptions;
const [sentences, setSentences] = useState<Sentence[]>([]);
const { language, voice, inferenceMode, voiceSpeed, hakkaToneMode, setLanguage, setVoice, screenshotMode } = queryOptions;
const [sentences, setSentences] = useState<Sentence[]>(
screenshotMode
? () => [
{ language: "waitau", voice: "male", inferenceMode: "online", voiceSpeed: 1, syllables: segment("天地玄黃,宇宙洪荒。") },
{ language: "waitau", voice: "female", inferenceMode: "online", voiceSpeed: 1, syllables: segment("日月盈昃,辰宿列張。") },
{ language: "hakka", voice: "male", inferenceMode: "online", voiceSpeed: 1, syllables: segment("天地玄黃,宇宙洪荒。") },
{ language: "hakka", voice: "female", inferenceMode: "online", voiceSpeed: 1, syllables: segment("日月盈昃,辰宿列張。") },
]
: [],
);

const textArea = useRef<HTMLTextAreaElement>(null);
const btnAddSentence = useRef<HTMLButtonElement>(null);
Expand Down Expand Up @@ -83,12 +92,12 @@ export default function App() {
<div>
<div className="text-secondary text-lg font-semibold ms-0.5 mb-0.5 tracking-widest">聲線</div>
<div className="join bg-base-100" role="group" aria-label="選擇聲線">
<Radio name="btnvoice" className="btn-secondary" state={voice} setState={setVoice} value="male" />
<Radio name="btnvoice" className="btn-secondary" state={voice} setState={setVoice} value="female" />
<Radio name="btnvoice" className="btn-secondary" state={screenshotMode ? language === "waitau" ? "male" : "female" : voice} setState={setVoice} value="male" />
<Radio name="btnvoice" className="btn-secondary" state={screenshotMode ? language === "waitau" ? "male" : "female" : voice} setState={setVoice} value="female" />
</div>
</div>
<div>
<button type="button" className="btn btn-ghost max-sm:btn-sm max-sm:px-2.5 relative flex-col flex-nowrap gap-0 text-base whitespace-nowrap h-20 min-h-20 text-slate-500 hover:bg-opacity-10" onClick={() => setCurrSettingsDialogPage("settings")}>
<button type="button" className="btn btn-ghost max-sm:btn-sm max-sm:px-2.5 relative flex-col flex-nowrap gap-0 text-base whitespace-nowrap h-20 min-h-20 text-slate-500 font-extrabold hover:bg-opacity-10" onClick={() => setCurrSettingsDialogPage("settings")}>
{currInferenceModeDownloadState !== "latest" && <MdError size="1.5em" className={`absolute -top-1 -right-1 ${DOWNLOAD_STATUS_INDICATOR_CLASS[currInferenceModeDownloadState]}`} />}
<MdSettings size="2em" />
設定
Expand Down Expand Up @@ -123,14 +132,19 @@ export default function App() {
</div>
</div>
<div className="mt-5">
{sentences.map((sentence, i) => (
<SentenceCard
key={sentences.length - i}
sentence={sentence}
hakkaToneMode={hakkaToneMode}
setDownloadState={setDownloadState}
currSettingsDialogPage={currSettingsDialogPage}
setCurrSettingsDialogPage={setCurrSettingsDialogPage} />
{sentences.flatMap((sentence, i) => (
!screenshotMode || sentence.language === language
? [
<SentenceCard
key={sentences.length - i}
sentence={sentence}
hakkaToneMode={hakkaToneMode}
setDownloadState={setDownloadState}
currSettingsDialogPage={currSettingsDialogPage}
setCurrSettingsDialogPage={setCurrSettingsDialogPage}
screenshotMode={screenshotMode} />,
]
: []
))}
</div>
</div>
Expand Down
13 changes: 8 additions & 5 deletions src/AudioPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export default function AudioPlayer({
setDownloadState,
currSettingsDialogPage,
setCurrSettingsDialogPage,
screenshotMode,
}: SentenceComponentState) {
const overrideSeekBar = screenshotMode && syllables[0][0] === "t";

useEffect(() => void context.resume(), []);
const [buffer, setBuffer] = useState<AudioBuffer | undefined>();
const [sourceNode, setSourceNode] = useState<AudioBufferSourceNode | undefined>();
Expand Down Expand Up @@ -84,7 +87,7 @@ export default function AudioPlayer({

useEffect(() => {
async function getDownloadComponents() {
if (inferenceMode === "online" || !db || downloadVersion || currSettingsDialogPage) return;
if (screenshotMode || inferenceMode === "online" || !db || downloadVersion || currSettingsDialogPage) return;
setDownloadVersion(undefined);
setDownloadError(undefined);
setBuffer(undefined);
Expand All @@ -107,7 +110,7 @@ export default function AudioPlayer({
const [generationRetryCounter, generationRetry] = useReducer((n: number) => n + 1, 0);
const text = syllables.join(" ");
useEffect(() => {
if (inferenceMode !== "online" && !downloadVersion) return;
if (screenshotMode || inferenceMode !== "online" && !downloadVersion) return;
async function generateAudio() {
const key = `${inferenceMode}/${voiceSpeed}/${downloadVersion}/${language}/${voice}`;
let textToBuffer = audioCache.get(key);
Expand Down Expand Up @@ -225,14 +228,14 @@ export default function AudioPlayer({
onClick={isPlaying === false ? playAudio : pauseAudio}
aria-label={isPlaying === false ? "播放" : "暫停"}
tabIndex={buffer ? 0 : -1}>
{isPlaying === false ? <MdPlayArrow /> : <MdPause />}
{!overrideSeekBar && isPlaying === false ? <MdPlayArrow /> : <MdPause />}
</button>
<input
type="range"
className="range range-warning range-sm grow mx-3 sm:mx-4"
min={0}
max={1}
value={progress}
value={overrideSeekBar ? 0.36 : progress}
step="any"
{...NO_AUTO_FILL}
onMouseDown={seekBarDown}
Expand All @@ -250,7 +253,7 @@ export default function AudioPlayer({
tabIndex={buffer ? 0 : -1}>
<MdStop />
</button>
{(error || !buffer) && <div className={`absolute inset-0 flex items-center justify-center ${error ? "bg-gray-300 bg-opacity-50 text-error" : "bg-gray-500 bg-opacity-20"} rounded-lg text-xl`}>
{!screenshotMode && (error || !buffer) && <div className={`absolute inset-0 flex items-center justify-center ${error ? "bg-gray-300 bg-opacity-50 text-error" : "bg-gray-500 bg-opacity-20"} rounded-lg text-xl`}>
{error
? <div>
<MdErrorOutline size="1.1875em" className="inline align-middle mt-0.5 mr-1" />
Expand Down
8 changes: 5 additions & 3 deletions src/SentenceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export default function SentenceCard({
setDownloadState,
currSettingsDialogPage,
setCurrSettingsDialogPage,
screenshotMode,
}: SentenceCardProps) {
const [enabledEdges, setEnabledEdges] = useState(new Set<Edge>());
const edges = useMemo(() => {
Expand Down Expand Up @@ -235,16 +236,17 @@ export default function SentenceCard({
<div className="join">
<span className="badge badge-primary join-item">{TERMINOLOGY[language]}</span>
<span className="badge badge-secondary join-item">{TERMINOLOGY[voice]}</span>
<span className="badge badge-accent join-item">{INFERENCE_MODE_TO_LABEL[inferenceMode]}</span>
<span className="badge badge-info join-item">{voiceSpeed}×</span>
{!screenshotMode && <span className="badge badge-accent join-item">{INFERENCE_MODE_TO_LABEL[inferenceMode]}</span>}
{!screenshotMode && <span className="badge badge-info join-item">{voiceSpeed}×</span>}
</div>
<SentenceCopy syllables={syllables} prons={flattenedProns} />
<div className="text-2.5xl/none sm:text-4xl mt-1">{tables}</div>
<AudioPlayer
sentence={{ language, voice, inferenceMode, voiceSpeed, syllables: inferenceMode === "lightweight" ? enabledEdgesProns : flattenedProns }}
setDownloadState={setDownloadState}
currSettingsDialogPage={currSettingsDialogPage}
setCurrSettingsDialogPage={setCurrSettingsDialogPage} />
setCurrSettingsDialogPage={setCurrSettingsDialogPage}
screenshotMode={screenshotMode} />
</div>
</div>;
}
4 changes: 2 additions & 2 deletions src/SettingsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ const SettingsDialog = forwardRef<HTMLDialogElement, SettingDialogProps>(functio
</span>
</button>
</form>
{currSettingsDialogPage && <h3 className="flex items-center gap-2 mx-6 mt-6 mb-4.5">
{currSettingsDialogPage && <h3 className="flex items-center gap-2 mx-6 mt-5.5 mb-5">
{currSettingsDialogPage === "settings"
? <>
<MdSettings size="1.125em" />設定
<MdSettings size="1.125em" className="mt-1" />設定
</>
: <>
<button type="button" className="btn btn-ghost w-14 h-14 min-h-14 text-4.5xl -ml-3 -mr-2.5 -my-7 text-slate-500 hover:bg-opacity-10" aria-label="返回" onClick={() => setCurrSettingsDialogPage("settings")}>
Expand Down
12 changes: 9 additions & 3 deletions src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ export function useQueryOptions(): QueryOptions {
mode: ALL_INFERENCE_MODES.find(mode => searchParams.has(mode)) || parseOption("mode", ALL_INFERENCE_MODES),
speed: +([searchParams.get("speed"), localStorage.getItem("speed")].find((speed): speed is string => !!speed && +speed >= 0.5 && +speed <= 2) || "1"),
hakka_tones: parseOption("hakka_tones", ALL_HAKKA_TONE_MODES),
screenshot: searchParams.has("screenshot"),
};
});
useEffect(() => {
Object.assign(localStorage, queryOptions);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { screenshot, ...rest } = queryOptions;
Object.assign(localStorage, rest);
}, [queryOptions]);
const { language, voice, mode: inferenceMode, speed: voiceSpeed, hakka_tones: hakkaToneMode } = queryOptions;
const { language, voice, mode: inferenceMode, speed: voiceSpeed, hakka_tones: hakkaToneMode, screenshot: screenshotMode } = queryOptions;
return {
language,
voice,
Expand All @@ -50,8 +53,11 @@ export function useQueryOptions(): QueryOptions {
setInferenceMode: (inferenceMode: InferenceMode) => setQueryOptions(oldOptions => ({ ...oldOptions, mode: inferenceMode })),
setVoiceSpeed: (voiceSpeed: number) => setQueryOptions(oldOptions => ({ ...oldOptions, speed: voiceSpeed })),
setHakkaToneMode: (hakkaToneMode: HakkaToneMode) => setQueryOptions(oldOptions => ({ ...oldOptions, hakka_tones: hakkaToneMode })),
screenshotMode,
get urlWithQuery() {
return `${location.origin}${location.pathname}?${String(new URLSearchParams(queryOptions as unknown as Record<string, string>))}`; // This is fine: number is automatically coalesced to string
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { screenshot, ...rest } = queryOptions;
return `${location.origin}${location.pathname}?${String(new URLSearchParams(rest as unknown as Record<string, string>))}`; // This is fine: number is automatically coalesced to string
},
};
}
Expand Down
3 changes: 3 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
a {
@apply link link-primary no-underline;
}
b {
@apply font-extrabold;
}
ruby {
@apply inline-flex flex-col-reverse items-center gap-0.5 align-bottom;
}
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export interface QueryOptions {
setInferenceMode: Dispatch<InferenceMode>;
setVoiceSpeed: Dispatch<number>;
setHakkaToneMode: Dispatch<HakkaToneMode>;
screenshotMode: boolean;
get urlWithQuery(): string;
}

Expand All @@ -163,6 +164,7 @@ export interface SettingsDialogState {

export interface SentenceComponentState extends SetDownloadStatus, SettingsDialogState {
sentence: Sentence;
screenshotMode: boolean;
}

export interface Actions {
Expand Down
2 changes: 1 addition & 1 deletion tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
extend: {
fontFamily: {
serif: [
"Chiron Sung HK",
// "Chiron Sung HK",
"Chiron Sung HK WS",
"Times New Roman",
"Times",
Expand Down

0 comments on commit 8ac5849

Please sign in to comment.