diff --git a/README.md b/README.md index a964312..af93a05 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# App Preview Converter +# 🍎 Ciderpress -Convert your videos to the required format for macOS and iOS App Store app previews. +Press your app preview videos into App Store perfection. -**Why this exists:** When uploading MP4 app recordings to Apple's App Store Connect, uploads often fail silently without any indication why. Apple secretly checks for specific video formatting requirements. This tool applies those formats to your video so it can be properly uploaded. +**Why this exists:** When uploading MP4 app recordings to Apple's App Store Connect, uploads often fail silently without any indication why. Apple secretly checks for specific video formatting requirements. Ciderpress applies those formats to your video so it can be properly uploaded. ## Features @@ -73,8 +73,8 @@ bun test # Run tests with coverage bun test:coverage -# Lint -bun lint +# Lint & format check +bun run check # Build for production bun run build @@ -87,6 +87,7 @@ bun run build - **Styling:** Tailwind CSS - **UI Components:** shadcn/ui + Magic UI - **Animation:** Motion (Framer Motion) +- **Linting:** Biome - **Testing:** Vitest + React Testing Library - **Video Processing:** FFmpeg (server-side) @@ -98,9 +99,8 @@ src/ │ ├── api/convert/ # Video conversion API endpoint │ └── page.tsx # Main page ├── components/ -│ ├── magicui/ # Magic UI components │ ├── providers/ # React context providers -│ ├── ui/ # shadcn/ui components +│ ├── ui/ # UI components (shadcn + custom) │ └── video-convert/ # Video conversion flow ├── hooks/ # Custom React hooks ├── lib/ # Utility functions diff --git a/src/__tests__/useTerminalMessages.test.ts b/src/__tests__/useTerminalMessages.test.ts index 6584567..31544d0 100644 --- a/src/__tests__/useTerminalMessages.test.ts +++ b/src/__tests__/useTerminalMessages.test.ts @@ -16,7 +16,7 @@ describe("useTerminalMessages", () => { result.current.initializeMessages(); }); - expect(result.current.messages).toHaveLength(2); + expect(result.current.messages).toHaveLength(3); expect(result.current.messages[0].text).toContain("Welcome"); expect(result.current.messages[0].type).toBe("info"); }); @@ -30,8 +30,8 @@ describe("useTerminalMessages", () => { result.current.addUploadPrompt(mockCallback); }); - expect(result.current.messages).toHaveLength(3); - const uploadPrompt = result.current.messages[2]; + expect(result.current.messages).toHaveLength(4); + const uploadPrompt = result.current.messages[3]; expect(uploadPrompt.type).toBe("prompt"); expect(uploadPrompt.buttons).toBeDefined(); expect(uploadPrompt.buttons?.[0].action).toBe("upload"); @@ -45,7 +45,7 @@ describe("useTerminalMessages", () => { result.current.addPlatformPrompt(); }); - const platformPrompt = result.current.messages[2]; + const platformPrompt = result.current.messages[3]; expect(platformPrompt.type).toBe("prompt"); expect(platformPrompt.buttons).toHaveLength(2); expect(platformPrompt.buttons?.[0].action).toBe("macos"); @@ -90,7 +90,7 @@ describe("useTerminalMessages", () => { expect(audioPrompt.buttons?.[1].action).toBe("audio-no"); }); - it("should add error message with warning emoji", () => { + it("should add error message with bruised apple indicator", () => { const { result } = renderHook(() => useTerminalMessages()); act(() => { @@ -98,7 +98,7 @@ describe("useTerminalMessages", () => { }); expect(result.current.messages[0].type).toBe("error"); - expect(result.current.messages[0].text).toContain("⚠️"); + expect(result.current.messages[0].text).toContain("Bruised apple"); expect(result.current.messages[0].text).toContain("Something went wrong"); }); @@ -129,6 +129,6 @@ describe("useTerminalMessages", () => { // Support message replaces all messages expect(result.current.messages).toHaveLength(1); - expect(result.current.messages[0].text).toContain("done"); + expect(result.current.messages[0].text).toContain("pressed"); }); }); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 5843782..6cd7303 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -10,21 +10,30 @@ const jetbrainsMono = JetBrains_Mono({ }); export const metadata: Metadata = { - title: "App Preview Converter", + title: "Ciderpress - App Preview Converter", description: - "Convert your app preview videos for macOS or iOS App Store submissions. Fixes common Apple upload rejections with proper formatting.", - keywords: ["app preview", "app store", "video converter", "macOS", "iOS", "ffmpeg", "apple"], + "Press your app preview videos into App Store perfection. Fixes common Apple upload rejections with proper formatting for macOS and iOS.", + keywords: [ + "app preview", + "app store", + "video converter", + "macOS", + "iOS", + "ffmpeg", + "apple", + "ciderpress", + ], authors: [{ name: "Brenden Bishop" }], openGraph: { - title: "App Preview Converter", - description: "Convert your app preview videos for macOS or iOS App Store submissions", + title: "Ciderpress", + description: "Press your app preview videos into App Store perfection", type: "website", locale: "en_US", }, twitter: { card: "summary", - title: "App Preview Converter", - description: "Convert your app preview videos for macOS or iOS App Store submissions", + title: "Ciderpress", + description: "Press your app preview videos into App Store perfection", }, robots: { index: true, diff --git a/src/components/terminal-content.tsx b/src/components/terminal-content.tsx index 6305a64..24c7a17 100644 --- a/src/components/terminal-content.tsx +++ b/src/components/terminal-content.tsx @@ -215,7 +215,7 @@ export default function TerminalContent({ }; return ( - + {isMounted && <>{messages.map((message, index) => renderMessage(message, index))}} ); diff --git a/src/components/ui/animated-upload-button.tsx b/src/components/ui/animated-upload-button.tsx index 6c32e1e..8c266ad 100644 --- a/src/components/ui/animated-upload-button.tsx +++ b/src/components/ui/animated-upload-button.tsx @@ -44,7 +44,7 @@ export const AnimatedUploadButton = React.forwardRef - Uploaded + Picked! @@ -68,7 +68,7 @@ export const AnimatedUploadButton = React.forwardRef - Uploading... + Picking... @@ -92,7 +92,7 @@ export const AnimatedUploadButton = React.forwardRef - Upload + Pick Apple diff --git a/src/components/ui/ciderpress-logo.tsx b/src/components/ui/ciderpress-logo.tsx new file mode 100644 index 0000000..aa38cce --- /dev/null +++ b/src/components/ui/ciderpress-logo.tsx @@ -0,0 +1,66 @@ +import { Apple } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface CiderpressLogoProps { + size?: "sm" | "md" | "lg" | "xl"; + className?: string; + showText?: boolean; +} + +const sizeMap = { + sm: { icon: 20, press: 16, gap: 1, text: "text-sm" }, + md: { icon: 28, press: 22, gap: 1.5, text: "text-lg" }, + lg: { icon: 40, press: 32, gap: 2, text: "text-2xl" }, + xl: { icon: 56, press: 44, gap: 3, text: "text-3xl" }, +}; + +function PressLines({ width, height, gap }: { width: number; height: number; gap: number }) { + const lineStyle = { width: `${width}px`, height: `${height}px` }; + return ( +
+
+
+
+
+ ); +} + +export function CiderpressLogo({ size = "md", className, showText = false }: CiderpressLogoProps) { + const { icon, press, gap, text } = sizeMap[size]; + const lineWidth = press * 0.4; + const lineHeight = press * 0.08; + + return ( +
+ {/* Logo Mark */} +
+ {/* Left Press Lines */} + + + {/* Apple Icon */} +
+ + {/* Juice Drop */} +
+
+ + {/* Right Press Lines */} + +
+ + {/* Wordmark */} + {showText && ( + + Ciderpress + + )} +
+ ); +} diff --git a/src/components/ui/terminal.tsx b/src/components/ui/terminal.tsx index 00a755a..2694be9 100644 --- a/src/components/ui/terminal.tsx +++ b/src/components/ui/terminal.tsx @@ -3,6 +3,7 @@ import { type MotionProps, motion } from "motion/react"; import { useCallback, useEffect, useRef, useState } from "react"; import { BorderBeam } from "@/components/ui/border-beam"; +import { CiderpressLogo } from "@/components/ui/ciderpress-logo"; import { cn } from "@/lib/utils"; // Animation timing constants @@ -237,7 +238,11 @@ export const Terminal = ({ children, className, title }: TerminalProps) => {
-
{title}
+ {title ? ( +
{title}
+ ) : ( + + )}
diff --git a/src/hooks/useTerminalMessages.ts b/src/hooks/useTerminalMessages.ts index 2b74951..e560edb 100644 --- a/src/hooks/useTerminalMessages.ts +++ b/src/hooks/useTerminalMessages.ts @@ -16,15 +16,20 @@ export const useTerminalMessages = () => { const initializeMessages = useCallback(() => { const initialMessages: TerminalMessage[] = [ { - text: "Welcome to App Preview Converter v1.0.0", + text: "🍎 Welcome to Ciderpress v1.0.0", delay: TIMING.INSTANT, // First message starts immediately type: "info", }, { - text: "This tool helps you convert videos for App Store submissions", + text: "App preview video rejected? Apple keeps the reasons to themselves.", delay: TIMING.BEAT, // Brief pause after welcome type: "info", }, + { + text: "We'll press your video into the format they actually accept.", + delay: TIMING.BEAT, + type: "info", + }, ]; setMessages(initialMessages); }, []); @@ -33,12 +38,12 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: "Upload a video to begin:", + text: "Drop an apple in the press to begin:", type: "prompt", delay: TIMING.PAUSE, // Pause before prompt buttons: [ { - text: "Upload", + text: "Pick Apple", action: "upload", onAction: (file?: File) => { if (file) { @@ -55,7 +60,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: `✓ ${fileName} uploaded successfully!`, + text: `🍏 ${fileName} picked successfully!`, delay: TIMING.INSTANT, // Immediate response type: "success", }, @@ -66,7 +71,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: "Which platform are you targeting?", + text: "Which orchard are you targeting?", delay: TIMING.BEAT, // Small pause after success type: "prompt", buttons: [ @@ -82,7 +87,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: `✓ Platform set to ${platform} (${resolution})`, + text: `✓ Orchard set to ${platform} (${resolution})`, delay: TIMING.INSTANT, type: "success", }, @@ -131,7 +136,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: "Starting video conversion...", + text: "🍏 Pressing...", delay: TIMING.BEAT, type: "info", }, @@ -142,12 +147,12 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: "✓ Video is now ready for App Preview upload!", + text: "🧃 Fresh cider ready! Your video is App Store approved.", delay: TIMING.PAUSE, // Pause for effect type: "success", buttons: [ - { text: "Download", action: "download", type: "rainbow" }, - { text: "New Conversion", action: "restart" }, + { text: "Bottle It", action: "download", type: "rainbow" }, + { text: "Press Another", action: "restart" }, ], }, ]); @@ -156,12 +161,12 @@ export const useTerminalMessages = () => { const addSupportMessage = useCallback(() => { setMessages([ { - text: "All done. Thank you & enjoy!", + text: "🍎 All pressed. Thank you & enjoy your cider!", delay: TIMING.INSTANT, type: "info", buttons: [ { text: "Buy me a coffee", action: "bmc", type: "bmc" }, - { text: "New Conversion", action: "restart" }, + { text: "Press Another", action: "restart" }, ], }, ]); @@ -171,7 +176,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: `⚠️ ${message}`, + text: `🍂 Bruised apple: ${message}`, delay: TIMING.INSTANT, type: "error", },