Skip to content

Commit 85c3f66

Browse files
feat: responsive design (#31)
1 parent 23b742e commit 85c3f66

20 files changed

+1041
-364
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@heroicons/react": "^2.1.4",
1919
"@huggingface/transformers": "^3.0.1",
2020
"@radix-ui/react-dropdown-menu": "^2.1.16",
21+
"@radix-ui/react-popover": "^1.1.15",
2122
"@radix-ui/react-progress": "^1.1.8",
2223
"@radix-ui/react-slider": "^1.3.6",
2324
"@react-input/mask": "^1.2.5",

src/LolApp.tsx

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Constants from "./transcriber/Constants";
77
import { Spinner } from "./ui/Spinner";
88
import { LandingDropzone } from "./screens/LandingDropzone";
99
import { Progress } from "./ui/Progress";
10-
import { Editor } from "./screens/editor/Editor.gen";
1110
import { makeEditorContextComponent } from "./screens/editor/EditorContext.gen";
1211
import { Transition } from "@headlessui/react";
1312
import type {
@@ -24,6 +23,7 @@ import { ShowErrorContext, UserFacingError } from "./ErrorBoundary";
2423
import { log } from "./hooks/useAnalytics";
2524
import HeartIcon from "@heroicons/react/20/solid/HeartIcon";
2625
import { ProductHuntIcon } from "./ui/Icons.res.mjs";
26+
import { Editor } from "./screens/editor/Editor.gen";
2727

2828
type VideoFile = {
2929
name: string;
@@ -339,12 +339,14 @@ export default function LolApp() {
339339
videoCodec: validVideoCodec,
340340
audioCodec: validAudioCodec,
341341
// Pass word animation data if word animation is enabled
342-
wordAnimationData: style.showWordAnimation && subtitlesManager.transcriptionState !== "TranscriptionInProgress"
343-
? {
344-
wordChunks: subtitlesManager.transcriptionState.wordChunks,
345-
cueRanges: subtitlesManager.transcriptionState.cueRanges,
346-
}
347-
: undefined,
342+
wordAnimationData:
343+
style.showWordAnimation &&
344+
subtitlesManager.transcriptionState !== "TranscriptionInProgress"
345+
? {
346+
wordChunks: subtitlesManager.transcriptionState.wordChunks,
347+
cueRanges: subtitlesManager.transcriptionState.cueRanges,
348+
}
349+
: undefined,
348350
},
349351
} as RenderWorkerMessage,
350352
[offscreenCanvas],
@@ -502,7 +504,7 @@ export default function LolApp() {
502504

503505
if (file && !transcriber.output) {
504506
return (
505-
<div className="container mx-auto flex items-center justify-center pt-[25%] flex-col">
507+
<div className="container mx-auto flex items-center justify-center px-4 flex-col h-dvh md:h-screen">
506508
<svg
507509
className="absolute inset-0 -z-10 h-full w-full stroke-white/10 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)]"
508510
aria-hidden="true"
@@ -533,14 +535,19 @@ export default function LolApp() {
533535
/>
534536
</svg>
535537

536-
<div className="flex items-center justify-center gap-4">
537-
<Spinner sizeRem={3} />
538-
<h1 className="text-5xl">{status}</h1>
538+
<div className="flex flex-col md:flex-row items-center justify-center gap-3 md:gap-4">
539+
<div className="md:hidden">
540+
<Spinner sizeRem={2} />
541+
</div>
542+
<div className="hidden md:block">
543+
<Spinner sizeRem={3} />
544+
</div>
545+
<h1 className="text-2xl md:text-5xl text-center">{status}</h1>
539546
</div>
540-
<p className="text-center text-balance text-gray-400 mt-4">
547+
<p className="text-center text-balance text-gray-400 text-sm md:text-base mt-4 px-2">
541548
{description}
542549
</p>
543-
<div className="w-full flex flex-col gap-y-2 mt-12 max-w-[34rem]">
550+
<div className="w-full flex flex-col gap-y-2 mt-8 md:mt-12 max-w-[34rem] px-4">
544551
{progressItems
545552
? progressItems.map((item) => (
546553
<Progress
@@ -592,23 +599,23 @@ export default function LolApp() {
592599
<Transition show={renderState !== "idle"}>
593600
<div
594601
className={clsx(
595-
"transition flex-col absolute z-[60] w-screen h-screen bg-white/10 backdrop-blur-xl inset-0 duration-300 ease-in data-[closed]:opacity-0 flex items-center justify-center",
602+
"transition flex-col absolute z-[60] w-screen h-dvh md:h-screen bg-white/10 backdrop-blur-xl inset-0 duration-300 ease-in data-[closed]:opacity-0 flex items-center justify-center px-4",
596603
renderState === "done" && "!bg-green-600/10 !backdrop-blur-2xl",
597604
renderState === "error" && "!bg-red-600/10 !backdrop-blur-2xl",
598605
)}
599606
>
600607
{renderState === "rendering" && (
601608
<>
602-
<h2 className="text-5xl tracking-wide font-bold">
609+
<h2 className="text-2xl md:text-5xl text-center tracking-wide font-bold">
603610
Rendering your video
604611
</h2>
605-
<p className="text-gray-300 text-balance text-center text-lg max-w-screen-sm mt-4">
612+
<p className="text-gray-300 text-balance text-center text-sm md:text-lg max-w-screen-sm mt-4">
606613
In a moment you'll get your video with subtitles created at the
607614
selected location. Feel free to move to the other tab, the
608615
render will continue in the background.
609616
</p>
610617

611-
<div className="w-full flex flex-col gap-y-2 mt-8 max-w-[34rem]">
618+
<div className="w-full flex flex-col gap-y-2 mt-6 md:mt-8 max-w-[34rem]">
612619
{progressItems
613620
? progressItems.map((item) => (
614621
<Progress
@@ -624,13 +631,13 @@ export default function LolApp() {
624631

625632
{renderState === "error" && (
626633
<>
627-
<h2 className="text-5xl tracking-wide font-bold text-red-400">
634+
<h2 className="text-2xl md:text-5xl text-center tracking-wide font-bold text-red-400">
628635
Rendering Failed
629636
</h2>
630-
<p className="text-gray-200 text-balance text-center max-w-screen-sm text-lg mt-4">
637+
<p className="text-gray-200 text-balance text-center max-w-screen-sm text-sm md:text-lg mt-4">
631638
{renderError || "An unknown error occurred during rendering."}
632639
</p>
633-
<p className="text-gray-400 text-balance text-center max-w-screen-md text-sm mt-2">
640+
<p className="text-gray-400 text-balance text-center max-w-screen-md text-xs md:text-sm mt-2">
634641
Try selecting a different video codec or format. Some codec
635642
combinations may not be supported by your browser.
636643
</p>
@@ -646,10 +653,10 @@ export default function LolApp() {
646653

647654
{renderState === "done" && (
648655
<>
649-
<h2 className="text-5xl tracking-wide font-bold">
656+
<h2 className="text-2xl md:text-5xl text-center tracking-wide font-bold">
650657
Video Rendered!
651658
</h2>
652-
<p className="text-gray-200 text-balance text-center max-w-screen-sm text-lg mt-4">
659+
<p className="text-gray-200 text-balance text-center max-w-screen-sm text-sm md:text-lg mt-4">
653660
You'll find your video in the location you selected a moment
654661
before. Time for publishing but before you do that ... just know
655662
... your video is amazing!
@@ -659,25 +666,25 @@ export default function LolApp() {
659666
<a
660667
href="https://www.producthunt.com/products/fframes-subtitles/reviews/new"
661668
rel="noopener noreferrer"
662-
className="mx-auto outline-none focus-visible:ring ring-orange-500 ring-offset-zinc-900 ring-offset-2 hover:bg-orange-400 transition rounded-lg gap-2 bg-orange-600 inline-flex items-center px-4 py-3 font-medium"
669+
className="mx-auto outline-none focus-visible:ring ring-orange-500 ring-offset-zinc-900 ring-offset-2 hover:bg-orange-400 transition rounded-lg gap-2 bg-orange-600 inline-flex items-center px-4 py-3 font-medium text-sm md:text-base"
663670
>
664-
<ProductHuntIcon.make className="size-6 text-orange-500" />
671+
<ProductHuntIcon.make className="size-5 md:size-6 text-orange-500" />
665672
Leave a Review
666673
</a>
667674

668675
<a
669676
href="https://github.com/sponsors/dmtrKovalenko"
670677
rel="noopener noreferrer"
671-
className="mx-auto outline-none focus-visible:ring ring-rose-500 ring-offset-zinc-900 ring-offset-2 hover:bg-rose-400 transition rounded-lg bg-rose-600 gap-2 inline-flex items-center px-4 py-3 font-medium"
678+
className="mx-auto outline-none focus-visible:ring ring-rose-500 ring-offset-zinc-900 ring-offset-2 hover:bg-rose-400 transition rounded-lg bg-rose-600 gap-2 inline-flex items-center px-4 py-3 font-medium text-sm md:text-base"
672679
>
673-
<HeartIcon className="size-6" />
680+
<HeartIcon className="size-5 md:size-6" />
674681
Support Author
675682
</a>
676683
</div>
677684

678685
<button
679686
onClick={handleBackToEditor}
680-
className="mt-6 text-gray-300 hover:text-white underline underline-offset-4 transition"
687+
className="mt-6 text-gray-300 hover:text-white underline underline-offset-4 transition text-sm md:text-base"
681688
>
682689
← Back to editor
683690
</button>

src/screens/LandingDropzone.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
4040
});
4141

4242
return (
43-
<div className="p-4 flex flex-col w-screen h-screen">
43+
<div className="p-2 md:p-4 flex flex-col w-screen h-dvh md:h-screen">
4444
<div
4545
{...getRootProps({
4646
onClick: (e) => {
@@ -53,7 +53,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
5353
},
5454
})}
5555
className={clsx(
56-
"mt-1 relative isolate flex-1 flex items-center flex-col w-full h-full justify-center rounded-2xl border-2 border-dashed p-6 border-gray-500 transition-colors focus:border-accent-500 focus:outline-none active:border-orange-400 focus:border-orange-400",
56+
"mt-1 relative isolate flex-1 flex items-center flex-col w-full h-full justify-center rounded-2xl border-2 border-dashed p-4 md:p-6 border-gray-500 transition-colors focus:border-accent-500 focus:outline-none active:border-orange-400 focus:border-orange-400",
5757
{
5858
"border-red-400": isDragReject,
5959
"border-blue-400": isDragActive,
@@ -93,24 +93,24 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
9393
</svg>
9494
{fileRejections.length > 0 && (
9595
<div className="mb-4 bg-red-200 px-4 py-2 shadow-red-400 shadow rounded-2xl">
96-
<p className="text-red-500 font-medium text-lg">
96+
<p className="text-red-500 font-medium text-base md:text-lg">
9797
Please upload a valid video file
9898
</p>
9999
</div>
100100
)}
101-
<div className="container flex-1 flex flex-col items-center justify-center">
102-
<h1 className="text-2xl text-center font-bold tracking-tight sm:text-6xl">
101+
<div className="container flex-1 flex flex-col items-center justify-center px-2 md:px-0">
102+
<h1 className="text-4xl text-center font-bold tracking-tight md:text-6xl">
103103
Free no-signup <span className="sr-only">automatic</span> AI{" "}
104104
<SubtitlesStrikethrough>captions</SubtitlesStrikethrough> generator
105105
</h1>
106-
<p className="mx-16 text-center text-balance mt-4 text-gray-400 text-xl">
106+
<p className="mx-0 md:mx-16 text-center text-balance mt-8 md:mt-4 text-gray-400 text-base md:text-xl">
107107
Upload a video to get the automatic transcription or translation and
108108
get your subtitles rendered back into the video file in just a few
109109
clicks completely for free with no signup required. Everything on
110110
this website is done entirely in your browser, ensuring that{" "}
111111
<strong>nothing is sent to the server</strong>.
112112
</p>
113-
<div className="mt-8 flex gap-6 justify-between mx-auto max-w-[34rem]">
113+
<div className="mt-6 md:mt-8 flex flex-col md:flex-row gap-3 md:gap-6 w-full md:w-auto md:justify-between mx-auto max-w-[34rem]">
114114
<Combobox
115115
options={ALL_LANGUAGES}
116116
selected={language}
@@ -146,28 +146,28 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
146146
/>
147147
<button
148148
onClick={open}
149-
className="mx-auto outline-none focus-visible:ring ring-orange-500 ring-offset-zinc-900 ring-offset-2 rounded-lg bg-orange-600 inline-flex items-center px-6 font-medium"
149+
className="mx-auto md:mx-0 w-full md:w-auto outline-none focus-visible:ring ring-orange-500 ring-offset-zinc-900 ring-offset-2 rounded-lg bg-orange-600 inline-flex items-center justify-center px-6 py-3 md:py-0 font-medium"
150150
>
151151
Let's go!
152152
</button>
153153
</div>
154154
{!window.showSaveFilePicker && (
155155
<div
156156
aria-hidden
157-
className="rounded-xl max-w-2xl mt-8 bg-amber-100 p-4"
157+
className="rounded-xl max-w-2xl mt-6 md:mt-8 bg-amber-100 p-3 md:p-4 mx-2 md:mx-0"
158158
>
159159
<div className="flex">
160-
<div className="flex-shrink-0">
160+
<div className="shrink-0">
161161
<ExclamationTriangleIcon
162162
aria-hidden="true"
163-
className="size-6 text-amber-500"
163+
className="size-5 md:size-6 text-amber-500"
164164
/>
165165
</div>
166166
<div className="ml-3">
167-
<h3 className="font-medium text-yellow-800">
167+
<h3 className="text-sm md:text-base font-medium text-yellow-800">
168168
Large file attention
169169
</h3>
170-
<div className="mt-1 text-sm text-yellow-700">
170+
<div className="mt-1 text-xs md:text-sm text-yellow-700">
171171
<p>
172172
Your browser does not support{" "}
173173
<a
@@ -189,7 +189,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
189189
</div>
190190
)}
191191
</div>
192-
<div className="mt-auto flex gap-6">
192+
<div className="mt-auto flex gap-6 py-2">
193193
<a
194194
target="_blank"
195195
rel="noopener noreferrer"
@@ -198,7 +198,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
198198
onClick={(e) => e.stopPropagation()}
199199
>
200200
<span className="sr-only">Producthunt</span>
201-
<ProductHuntIcon.make className="size-7 text-black" />
201+
<ProductHuntIcon.make className="size-6 md:size-7 text-black" />
202202
</a>
203203

204204
<a
@@ -209,7 +209,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
209209
onClick={(e) => e.stopPropagation()}
210210
>
211211
<span className="sr-only">Project sources</span>
212-
<GithubIcon className="transition size-7 hover:scale-125 active:scale-90 hover:text-orange-500" />
212+
<GithubIcon className="transition size-6 md:size-7 hover:scale-125 active:scale-90 hover:text-orange-500" />
213213
</a>
214214
<a
215215
target="_blank"
@@ -219,7 +219,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
219219
onClick={(e) => e.stopPropagation()}
220220
>
221221
<span className="sr-only">Follow on twitter</span>
222-
<TwitterIcon className="transition size-7 hover:scale-125 active:scale-90 hover:text-orange-500" />
222+
<TwitterIcon className="transition size-6 md:size-7 hover:scale-125 active:scale-90 hover:text-orange-500" />
223223
</a>
224224
<a
225225
target="_blank"
@@ -231,7 +231,7 @@ export const LandingDropzone: React.FC<LandingDropzoneProps> = ({
231231
<span className="sr-only">Support this project developlment</span>
232232
<HeartIcon
233233
aria-hidden
234-
className="transition size-7 hover:scale-125 active:scale-90 hover:text-orange-500"
234+
className="transition size-6 md:size-7 hover:scale-125 active:scale-90 hover:text-orange-500"
235235
/>
236236
</a>
237237
</div>

src/screens/editor/ChunksList/ChunkEditor.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ let make = React.memo((
125125
el =>
126126
el->Webapi.Dom.Element.scrollIntoViewWithOptions({
127127
"behavior": "smooth",
128-
"block": "start",
128+
"block": "nearest",
129129
}),
130130
)
131131
}

src/screens/editor/ChunksList/ChunkEditor.res.mjs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/screens/editor/ChunksList/ChunksList.res

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ let make = React.memo((~subtitlesManager, ~title: React.element) => {
430430
let (player, _) = ctx.usePlayer()
431431

432432
<>
433-
<div className="sticky top-0 z-10 px-2 bg-zinc-900 flex flex-col w-full">
433+
<div
434+
className="sticky -top-px z-10 py-2 flex flex-col w-full bg-zinc-950 md:bg-zinc-900/95 md:backdrop-blur-sm border-b border-zinc-800/50">
434435
<h2 className="mx-auto text-xl pb-2"> {title} </h2>
435436
{switch subtitlesManager.transcriptionState {
436437
| SubtitlesReady({size}) =>

src/screens/editor/ChunksList/ChunksList.res.mjs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)