From d6b0adaff5c5c4e990b73d255d98426510d9270f Mon Sep 17 00:00:00 2001 From: Brenden Bishop Date: Wed, 31 Dec 2025 14:44:42 -0500 Subject: [PATCH 1/3] feat: add Ciderpress logo component - Apple icon with press lines and juice drop animation - Replaces text title in terminal header --- src/components/terminal-content.tsx | 2 +- src/components/ui/ciderpress-logo.tsx | 66 +++++++++++++++++++++++++++ src/components/ui/terminal.tsx | 7 ++- 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/components/ui/ciderpress-logo.tsx 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/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}
+ ) : ( + + )}
From bd0b5b754d510f109faf6363e1818c0cf1cbead6 Mon Sep 17 00:00:00 2001 From: Brenden Bishop Date: Wed, 31 Dec 2025 14:47:31 -0500 Subject: [PATCH 2/3] feat: rebrand to Ciderpress with apple-themed copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update all terminal messages with cider press metaphor - "Upload" → "Pick Apple", "Converting" → "Pressing" - "Complete" → "Fresh cider ready!", errors → "Bruised apple" - Update metadata, README, and button text - Update tests to match new copy --- README.md | 14 +++++----- src/__tests__/useTerminalMessages.test.ts | 6 ++--- src/app/layout.tsx | 23 +++++++++++----- src/components/ui/animated-upload-button.tsx | 6 ++--- src/hooks/useTerminalMessages.ts | 28 ++++++++++---------- 5 files changed, 43 insertions(+), 34 deletions(-) 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..86a01c0 100644 --- a/src/__tests__/useTerminalMessages.test.ts +++ b/src/__tests__/useTerminalMessages.test.ts @@ -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/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/hooks/useTerminalMessages.ts b/src/hooks/useTerminalMessages.ts index 2b74951..b8923eb 100644 --- a/src/hooks/useTerminalMessages.ts +++ b/src/hooks/useTerminalMessages.ts @@ -16,12 +16,12 @@ 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: "Press your app preview videos into App Store perfection", delay: TIMING.BEAT, // Brief pause after welcome type: "info", }, @@ -33,12 +33,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 +55,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: `✓ ${fileName} uploaded successfully!`, + text: `🍏 ${fileName} picked successfully!`, delay: TIMING.INSTANT, // Immediate response type: "success", }, @@ -66,7 +66,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 +82,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 +131,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: "Starting video conversion...", + text: "🍏 Pressing...", delay: TIMING.BEAT, type: "info", }, @@ -142,12 +142,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 +156,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 +171,7 @@ export const useTerminalMessages = () => { setMessages((prev) => [ ...prev, { - text: `⚠️ ${message}`, + text: `🍂 Bruised apple: ${message}`, delay: TIMING.INSTANT, type: "error", }, From a463d53d854180ae0a90903bb3248b1008c25988 Mon Sep 17 00:00:00 2001 From: Brenden Bishop Date: Wed, 31 Dec 2025 14:53:59 -0500 Subject: [PATCH 3/3] chore: copy updates --- src/__tests__/useTerminalMessages.test.ts | 8 ++++---- src/hooks/useTerminalMessages.ts | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/__tests__/useTerminalMessages.test.ts b/src/__tests__/useTerminalMessages.test.ts index 86a01c0..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"); diff --git a/src/hooks/useTerminalMessages.ts b/src/hooks/useTerminalMessages.ts index b8923eb..e560edb 100644 --- a/src/hooks/useTerminalMessages.ts +++ b/src/hooks/useTerminalMessages.ts @@ -21,10 +21,15 @@ export const useTerminalMessages = () => { type: "info", }, { - text: "Press your app preview videos into App Store perfection", + 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); }, []);