Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
/* ── Light mode tokens ── */
:root {
--bg: #ffffff;
--surface: #f1f5f9;
--border: #cbd5e1;
--surface: #f8fafc;
--border: #e2e8f0;
--text: #0f172a;
--muted: #64748b;
--accent: #3b82f6;
Expand Down Expand Up @@ -140,7 +140,7 @@ textarea:focus {
}

:focus-visible {
outline: 0;
box-shadow: 0 0 0 3px var(--accent-muted);
border-radius: var(--radius);
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
}
5 changes: 1 addition & 4 deletions src/components/DownloadResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ export default function DownloadResult({ result, onReset, soundOnCompletion, onT
useEffect(() => {
if (soundOnCompletion) {
const audio = new Audio("/sounds/export-complete.mp3");
audio.play().catch((error) => {
console.error("Failed to play completion sound:", error);
setSoundError(true);
});
audio.play().catch((err) => console.error(err));
}
}, [soundOnCompletion]);
const handleReset = () => {
Expand Down
18 changes: 9 additions & 9 deletions src/components/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function FileUpload({

// ── File info (shown after upload) ───────────────────
const FileInfo = () => (
<div className="px-4 py-3 bg-[var(--surface)] border border-[var(--border)] rounded-[var(--radius)] shadow-[var(--shadow)]">
<div className="px-4 py-3 bg-film-50 border border-film-200 rounded-lg">
<div className="flex flex-col lg:flex-row lg:items-center gap-3">
<div className="flex items-start gap-3 flex-1 min-w-0">
<div className="hidden lg:flex items-center justify-center w-9 h-9 rounded-lg bg-[var(--surface)] border border-[var(--border)] shrink-0">
Expand All @@ -136,18 +136,18 @@ export default function FileUpload({
<Film size={18} className="lg:hidden text-film-600 shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-2 mb-0.5">
<p className="text-sm font-semibold text-[var(--text)] truncate max-w-[320px] xl:max-w-[420px]">
<p className="text-sm font-semibold text-film-700 truncate max-w-[320px] xl:max-w-[420px]">
{currentFile?.name}
</p>
{currentFile && (
<span className="px-2 py-0.5 bg-[var(--accent-muted)] text-[var(--text)] font-bold tracking-wider rounded text-[10px] uppercase shrink-0">
<span className="px-2 py-0.5 bg-gray-700 text-white font-bold tracking-wider rounded text-[10px] uppercase shrink-0">
{currentFile.name.includes(".")
? currentFile.name.split(".").pop()
: "VIDEO"}
</span>
)}
</div>
<div className="text-xs text-[var(--muted)] mt-1 space-y-0.5">
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 space-y-0.5">
<p>{formatBytes(currentFile?.size ?? 0)}</p>
<p>
{duration > 0
Expand All @@ -168,12 +168,12 @@ export default function FileUpload({
</button>
</div>

<p className="text-xs text-[var(--muted)] mt-3 break-words">
<p className="text-xs text-gray-500 mt-3 break-words">
Supports: MP4, MOV, AVI, MKV, WebM, and most video formats
</p>

{fileError && (
<p className="text-xs text-[var(--error)] mt-2 font-medium">{fileError}</p>
<p className="text-xs text-red-500 mt-2 font-medium">{fileError}</p>
)}

<input
Expand Down Expand Up @@ -296,17 +296,17 @@ export default function FileUpload({
{/* ── Normal upload UI ── */}
<div className="space-y-2">
{error && (
<p role="alert" className="text-sm text-[var(--error)]">
<p role="alert" className="text-sm text-red-500">
{error}
</p>
)}
{warning && (
<p role="alert" className="text-sm text-[var(--warning)]">
<p role="alert" className="text-sm text-yellow-500">
{warning}
</p>
)}
{currentFile ? <FileInfo /> : <DropZone />}
</div>
</>
);
}
}
20 changes: 10 additions & 10 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ export default function Footer() {
].map((tag) => (
<span
key={tag.label}
className="flex items-center gap-1.5 px-3 py-1 rounded-lg border border-[var(--border)] bg-[var(--surface)] text-[10px] font-semibold tracking-wide uppercase transition-all duration-200 ease-in-out hover:-translate-y-0.5 hover:border-[var(--accent)] hover:bg-[var(--accent-muted)] hover:shadow-[var(--shadow)] cursor-pointer select-none"
className="flex items-center gap-1.5 px-3 py-1 rounded-lg border border-[var(--border)] bg-[var(--surface)] text-[10px] font-semibold tracking-wide uppercase transition-all duration-200 ease-in-out hover:-translate-y-0.5 hover:border-[var(--accent)] hover:shadow-[0_0_10px_rgba(255,255,255,0.08)] cursor-pointer select-none"
>
{tag.icon} {tag.label}
</span>
))}
</div>
</div>


{/* Links Section */}
<div className="md:col-span-3 space-y-5">
<h3 className="text-[10px] font-bold uppercase tracking-[0.2em] opacity-40">
Expand All @@ -59,19 +60,19 @@ export default function Footer() {
href="https://github.com/magic-peach/reframe"
target="_blank"
rel="noopener"
className="opacity-70 hover:opacity-100 hover:text-[var(--accent)] hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
className="opacity-70 hover:opacity-100 hover:text-red-400 hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
>
GitHub
</a>
<Link
href="/contact"
className="opacity-70 hover:opacity-100 hover:text-[var(--accent)] hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
className="opacity-70 hover:opacity-100 hover:text-red-400 hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
>
Contact
</Link>
<Link
href="/privacy"
className="opacity-70 hover:opacity-100 hover:text-[var(--accent)] hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
className="opacity-70 hover:opacity-100 hover:text-red-400 hover:scale-110 transition-all duration-500 ease-in-out w-fit flex items-center gap-2 group"
>
Privacy Policy
</Link>
Expand Down Expand Up @@ -102,7 +103,7 @@ export default function Footer() {
) : (
<div
id="updates-signup-form"
className="w-full sm:w-72 px-4 flex items-center bg-[var(--surface)] border border-[var(--accent)] rounded-lg transition-all duration-500 ease-in-out"
className="w-full sm:w-72 px-4 flex items-center bg-[var(--surface)] border border-blue-500/50 rounded-lg transition-all duration-500 ease-in-out"
>
<form
aria-label="Updates signup form"
Expand All @@ -122,7 +123,7 @@ export default function Footer() {
<button
aria-label="Submit email for updates"
type="submit"
className="text-[var(--accent)] hover:text-[var(--accent-hover)] p-1"
className="text-blue-500 hover:text-blue-400 p-1"
>
<ArrowRight size={16} aria-hidden="true" />
</button>
Expand All @@ -143,7 +144,7 @@ export default function Footer() {
href="https://github.com/magic-peach/reframe"
target="_blank"
rel="noopener"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:border-[var(--accent)] hover:bg-[var(--accent-muted)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:bg-[var(--border)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
aria-label="Open Reframe GitHub repository"
>
<Github
Expand All @@ -157,7 +158,7 @@ export default function Footer() {
href="https://twitter.com"
target="_blank"
rel="noopener"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:border-[var(--accent)] hover:bg-[var(--accent-muted)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:bg-[var(--border)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
aria-label="Open Twitter"
>
<TwitterIcon
Expand All @@ -171,7 +172,7 @@ export default function Footer() {
href="https://instagram.com"
target="_blank"
rel="noopener"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:border-[var(--accent)] hover:bg-[var(--accent-muted)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
className="p-2.5 rounded-lg border border-[var(--border)] bg-[var(--surface)] hover:bg-[var(--border)] transition-all hover:-translate-y-1 active:scale-95 flex items-center justify-center group"
aria-label="Open Instagram"
>
<Instagram
Expand All @@ -184,7 +185,6 @@ export default function Footer() {
</div>
</div>
</div>

{/* Bottom Bar */}
<div className="max-w-7xl mx-auto mt-16 pt-8 border-t border-[var(--border)] flex flex-col md:flex-row justify-between items-center gap-4 text-[9px] font-bold uppercase tracking-[0.3em] opacity-40">
<p>© {new Date().getFullYear()} Reframe · MIT License</p>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ImageOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function ImageOverlayPanel({
type="button"
onClick={() => setOverlayFile(null)}
aria-label="Remove overlay image"
className="w-6 h-6 rounded flex items-center justify-center bg-[var(--error-bg)] hover:bg-[var(--error-hover)] text-[var(--error)] border border-[var(--error-border)] transition shrink-0"
className="w-6 h-6 rounded flex items-center justify-center bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 transition shrink-0"
>
<Trash2 size={11} aria-hidden="true" />
</button>
Expand Down
45 changes: 35 additions & 10 deletions src/components/OnboardingTour.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export default function OnboardingTour() {
const [visible, setVisible] = useState(false);
const [targetRect, setTargetRect] = useState<Rect | null>(null);
const tooltipRef = useRef<HTMLDivElement>(null);
const isFirstRender = useRef(true);
const isFirstRender = useRef(true);
const currentStep = TOUR_STEPS[stepIndex];

const dismiss = useCallback(() => {
Expand Down Expand Up @@ -269,16 +269,41 @@ export default function OnboardingTour() {

// Initialise on mount
useEffect(() => {
if (localStorage.getItem(TOUR_KEY)) return;
const t = setTimeout(async () => {
const rect = await measureTarget(TOUR_STEPS[0]?.targetId ?? "");
if (rect) {
setTargetRect(rect);
setVisible(true);
if (localStorage.getItem(TOUR_KEY)) return;
const t = setTimeout(async () => {
const rect = await measureTarget(TOUR_STEPS[0]?.targetId ?? "");
if (rect) {
setTargetRect(rect);
setVisible(true);
}
}, 600);
return () => clearTimeout(t);
}, [measureTarget]);

// Measure target whenever step changes (skip on first render — init effect handles that)
useEffect(() => {
if (!visible) return;
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
if (!currentStep) {
dismiss();
return;
}
measureTarget(currentStep.targetId).then((rect) => {
if (rect) {
setTargetRect(rect);
setTimeout(() => tooltipRef.current?.focus(), 50);
} else {
if (stepIndex < TOUR_STEPS.length - 1) {
setStepIndex((i) => i + 1);
} else {
dismiss();
}
}, 600);
return () => clearTimeout(t);
}, [measureTarget]);
}
});
}, [stepIndex, visible, measureTarget, dismiss, currentStep]);

// Measure target whenever step changes (skip on first render — init effect handles that)
useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/PresetSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default function PresetSelector({ recipe, onChange }: Props) {
return (
<div className="space-y-3">
{/* Quick-action row */}
<div className="grid grid-cols-5 gap-1.5">
<div className="grid grid-cols-3 md:grid-cols-5 gap-1.5">
{QUICK_ACTIONS.map(({ preset, label, platform, icon }) => {
const isActive = recipe.preset === preset;
return (
Expand Down
7 changes: 3 additions & 4 deletions src/components/ThemeToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ export function ThemeToggle() {
bg-[var(--surface)]
text-[var(--text)]
border border-[var(--border)]
hover:border-[var(--accent)] hover:bg-[var(--accent-muted)]
focus:outline-none focus:ring-2 focus:ring-[var(--accent)] focus:ring-offset-2
focus:ring-offset-[var(--bg)]
transition-all duration-200
hover:opacity-90
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
transition-colors duration-200
"
>
{isDark ? (
Expand Down
Loading
Loading