Skip to content

Commit 6dae5f2

Browse files
authored
Merge pull request #2 from btbishop93/feat/ci-biome-tests
Feat/new theme for application
2 parents e6ad498 + a463d53 commit 6dae5f2

8 files changed

Lines changed: 125 additions & 40 deletions

File tree

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# App Preview Converter
1+
# 🍎 Ciderpress
22

3-
Convert your videos to the required format for macOS and iOS App Store app previews.
3+
Press your app preview videos into App Store perfection.
44

5-
**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.
5+
**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.
66

77
## Features
88

@@ -73,8 +73,8 @@ bun test
7373
# Run tests with coverage
7474
bun test:coverage
7575

76-
# Lint
77-
bun lint
76+
# Lint & format check
77+
bun run check
7878

7979
# Build for production
8080
bun run build
@@ -87,6 +87,7 @@ bun run build
8787
- **Styling:** Tailwind CSS
8888
- **UI Components:** shadcn/ui + Magic UI
8989
- **Animation:** Motion (Framer Motion)
90+
- **Linting:** Biome
9091
- **Testing:** Vitest + React Testing Library
9192
- **Video Processing:** FFmpeg (server-side)
9293

@@ -98,9 +99,8 @@ src/
9899
│ ├── api/convert/ # Video conversion API endpoint
99100
│ └── page.tsx # Main page
100101
├── components/
101-
│ ├── magicui/ # Magic UI components
102102
│ ├── providers/ # React context providers
103-
│ ├── ui/ # shadcn/ui components
103+
│ ├── ui/ # UI components (shadcn + custom)
104104
│ └── video-convert/ # Video conversion flow
105105
├── hooks/ # Custom React hooks
106106
├── lib/ # Utility functions

src/__tests__/useTerminalMessages.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe("useTerminalMessages", () => {
1616
result.current.initializeMessages();
1717
});
1818

19-
expect(result.current.messages).toHaveLength(2);
19+
expect(result.current.messages).toHaveLength(3);
2020
expect(result.current.messages[0].text).toContain("Welcome");
2121
expect(result.current.messages[0].type).toBe("info");
2222
});
@@ -30,8 +30,8 @@ describe("useTerminalMessages", () => {
3030
result.current.addUploadPrompt(mockCallback);
3131
});
3232

33-
expect(result.current.messages).toHaveLength(3);
34-
const uploadPrompt = result.current.messages[2];
33+
expect(result.current.messages).toHaveLength(4);
34+
const uploadPrompt = result.current.messages[3];
3535
expect(uploadPrompt.type).toBe("prompt");
3636
expect(uploadPrompt.buttons).toBeDefined();
3737
expect(uploadPrompt.buttons?.[0].action).toBe("upload");
@@ -45,7 +45,7 @@ describe("useTerminalMessages", () => {
4545
result.current.addPlatformPrompt();
4646
});
4747

48-
const platformPrompt = result.current.messages[2];
48+
const platformPrompt = result.current.messages[3];
4949
expect(platformPrompt.type).toBe("prompt");
5050
expect(platformPrompt.buttons).toHaveLength(2);
5151
expect(platformPrompt.buttons?.[0].action).toBe("macos");
@@ -90,15 +90,15 @@ describe("useTerminalMessages", () => {
9090
expect(audioPrompt.buttons?.[1].action).toBe("audio-no");
9191
});
9292

93-
it("should add error message with warning emoji", () => {
93+
it("should add error message with bruised apple indicator", () => {
9494
const { result } = renderHook(() => useTerminalMessages());
9595

9696
act(() => {
9797
result.current.addErrorMessage("Something went wrong");
9898
});
9999

100100
expect(result.current.messages[0].type).toBe("error");
101-
expect(result.current.messages[0].text).toContain("⚠️");
101+
expect(result.current.messages[0].text).toContain("Bruised apple");
102102
expect(result.current.messages[0].text).toContain("Something went wrong");
103103
});
104104

@@ -129,6 +129,6 @@ describe("useTerminalMessages", () => {
129129

130130
// Support message replaces all messages
131131
expect(result.current.messages).toHaveLength(1);
132-
expect(result.current.messages[0].text).toContain("done");
132+
expect(result.current.messages[0].text).toContain("pressed");
133133
});
134134
});

src/app/layout.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,30 @@ const jetbrainsMono = JetBrains_Mono({
1010
});
1111

1212
export const metadata: Metadata = {
13-
title: "App Preview Converter",
13+
title: "Ciderpress - App Preview Converter",
1414
description:
15-
"Convert your app preview videos for macOS or iOS App Store submissions. Fixes common Apple upload rejections with proper formatting.",
16-
keywords: ["app preview", "app store", "video converter", "macOS", "iOS", "ffmpeg", "apple"],
15+
"Press your app preview videos into App Store perfection. Fixes common Apple upload rejections with proper formatting for macOS and iOS.",
16+
keywords: [
17+
"app preview",
18+
"app store",
19+
"video converter",
20+
"macOS",
21+
"iOS",
22+
"ffmpeg",
23+
"apple",
24+
"ciderpress",
25+
],
1726
authors: [{ name: "Brenden Bishop" }],
1827
openGraph: {
19-
title: "App Preview Converter",
20-
description: "Convert your app preview videos for macOS or iOS App Store submissions",
28+
title: "Ciderpress",
29+
description: "Press your app preview videos into App Store perfection",
2130
type: "website",
2231
locale: "en_US",
2332
},
2433
twitter: {
2534
card: "summary",
26-
title: "App Preview Converter",
27-
description: "Convert your app preview videos for macOS or iOS App Store submissions",
35+
title: "Ciderpress",
36+
description: "Press your app preview videos into App Store perfection",
2837
},
2938
robots: {
3039
index: true,

src/components/terminal-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export default function TerminalContent({
215215
};
216216

217217
return (
218-
<Terminal title="App Preview Converter">
218+
<Terminal>
219219
{isMounted && <>{messages.map((message, index) => renderMessage(message, index))}</>}
220220
</Terminal>
221221
);

src/components/ui/animated-upload-button.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const AnimatedUploadButton = React.forwardRef<HTMLButtonElement, Animated
4444
>
4545
<span className="inline-flex items-center">
4646
<Check className="mr-2 size-4" />
47-
Uploaded
47+
Picked!
4848
</span>
4949
</motion.span>
5050
</motion.button>
@@ -68,7 +68,7 @@ export const AnimatedUploadButton = React.forwardRef<HTMLButtonElement, Animated
6868
>
6969
<span className="inline-flex items-center">
7070
<Loader2 className="mr-2 size-4 animate-spin" />
71-
Uploading...
71+
Picking...
7272
</span>
7373
</motion.span>
7474
</motion.button>
@@ -92,7 +92,7 @@ export const AnimatedUploadButton = React.forwardRef<HTMLButtonElement, Animated
9292
exit={{ x: 50, transition: { duration: 0.1 } }}
9393
>
9494
<span className="group inline-flex items-center">
95-
Upload
95+
Pick Apple
9696
<Upload className="ml-2 size-4 transition-transform duration-300 group-hover:translate-y-[-2px]" />
9797
</span>
9898
</motion.span>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Apple } from "lucide-react";
2+
import { cn } from "@/lib/utils";
3+
4+
interface CiderpressLogoProps {
5+
size?: "sm" | "md" | "lg" | "xl";
6+
className?: string;
7+
showText?: boolean;
8+
}
9+
10+
const sizeMap = {
11+
sm: { icon: 20, press: 16, gap: 1, text: "text-sm" },
12+
md: { icon: 28, press: 22, gap: 1.5, text: "text-lg" },
13+
lg: { icon: 40, press: 32, gap: 2, text: "text-2xl" },
14+
xl: { icon: 56, press: 44, gap: 3, text: "text-3xl" },
15+
};
16+
17+
function PressLines({ width, height, gap }: { width: number; height: number; gap: number }) {
18+
const lineStyle = { width: `${width}px`, height: `${height}px` };
19+
return (
20+
<div className="flex flex-col justify-center" style={{ gap: `${gap}px` }}>
21+
<div className="bg-amber-500 rounded-full" style={lineStyle} />
22+
<div className="bg-amber-500 rounded-full" style={lineStyle} />
23+
<div className="bg-amber-500 rounded-full" style={lineStyle} />
24+
</div>
25+
);
26+
}
27+
28+
export function CiderpressLogo({ size = "md", className, showText = false }: CiderpressLogoProps) {
29+
const { icon, press, gap, text } = sizeMap[size];
30+
const lineWidth = press * 0.4;
31+
const lineHeight = press * 0.08;
32+
33+
return (
34+
<div className={cn("flex items-center", showText && "gap-3", className)}>
35+
{/* Logo Mark */}
36+
<div className="relative flex items-center" style={{ gap: `${gap * 4}px` }}>
37+
{/* Left Press Lines */}
38+
<PressLines width={lineWidth} height={lineHeight} gap={gap} />
39+
40+
{/* Apple Icon */}
41+
<div className="relative">
42+
<Apple size={icon} className="text-red-500 fill-red-500/20" strokeWidth={1.5} />
43+
{/* Juice Drop */}
44+
<div
45+
className="absolute left-1/2 -translate-x-1/2 bg-amber-400 rounded-full animate-pulse"
46+
style={{
47+
width: `${icon * 0.15}px`,
48+
height: `${icon * 0.2}px`,
49+
bottom: `${-icon * 0.15}px`,
50+
}}
51+
/>
52+
</div>
53+
54+
{/* Right Press Lines */}
55+
<PressLines width={lineWidth} height={lineHeight} gap={gap} />
56+
</div>
57+
58+
{/* Wordmark */}
59+
{showText && (
60+
<span className={cn("font-mono font-bold tracking-tight text-white", text)}>
61+
Ciderpress
62+
</span>
63+
)}
64+
</div>
65+
);
66+
}

src/components/ui/terminal.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { type MotionProps, motion } from "motion/react";
44
import { useCallback, useEffect, useRef, useState } from "react";
55
import { BorderBeam } from "@/components/ui/border-beam";
6+
import { CiderpressLogo } from "@/components/ui/ciderpress-logo";
67
import { cn } from "@/lib/utils";
78

89
// Animation timing constants
@@ -237,7 +238,11 @@ export const Terminal = ({ children, className, title }: TerminalProps) => {
237238
<div className="h-3 w-3 rounded-full bg-yellow-500/80 hover:bg-yellow-500 transition-colors"></div>
238239
<div className="h-3 w-3 rounded-full bg-green-500/80 hover:bg-green-500 transition-colors"></div>
239240
</div>
240-
<div className="text-sm font-mono text-neutral-300 tracking-tight">{title}</div>
241+
{title ? (
242+
<div className="text-sm font-mono text-neutral-300 tracking-tight">{title}</div>
243+
) : (
244+
<CiderpressLogo size="sm" showText />
245+
)}
241246
</div>
242247
</div>
243248

src/hooks/useTerminalMessages.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,20 @@ export const useTerminalMessages = () => {
1616
const initializeMessages = useCallback(() => {
1717
const initialMessages: TerminalMessage[] = [
1818
{
19-
text: "Welcome to App Preview Converter v1.0.0",
19+
text: "🍎 Welcome to Ciderpress v1.0.0",
2020
delay: TIMING.INSTANT, // First message starts immediately
2121
type: "info",
2222
},
2323
{
24-
text: "This tool helps you convert videos for App Store submissions",
24+
text: "App preview video rejected? Apple keeps the reasons to themselves.",
2525
delay: TIMING.BEAT, // Brief pause after welcome
2626
type: "info",
2727
},
28+
{
29+
text: "We'll press your video into the format they actually accept.",
30+
delay: TIMING.BEAT,
31+
type: "info",
32+
},
2833
];
2934
setMessages(initialMessages);
3035
}, []);
@@ -33,12 +38,12 @@ export const useTerminalMessages = () => {
3338
setMessages((prev) => [
3439
...prev,
3540
{
36-
text: "Upload a video to begin:",
41+
text: "Drop an apple in the press to begin:",
3742
type: "prompt",
3843
delay: TIMING.PAUSE, // Pause before prompt
3944
buttons: [
4045
{
41-
text: "Upload",
46+
text: "Pick Apple",
4247
action: "upload",
4348
onAction: (file?: File) => {
4449
if (file) {
@@ -55,7 +60,7 @@ export const useTerminalMessages = () => {
5560
setMessages((prev) => [
5661
...prev,
5762
{
58-
text: ` ${fileName} uploaded successfully!`,
63+
text: `🍏 ${fileName} picked successfully!`,
5964
delay: TIMING.INSTANT, // Immediate response
6065
type: "success",
6166
},
@@ -66,7 +71,7 @@ export const useTerminalMessages = () => {
6671
setMessages((prev) => [
6772
...prev,
6873
{
69-
text: "Which platform are you targeting?",
74+
text: "Which orchard are you targeting?",
7075
delay: TIMING.BEAT, // Small pause after success
7176
type: "prompt",
7277
buttons: [
@@ -82,7 +87,7 @@ export const useTerminalMessages = () => {
8287
setMessages((prev) => [
8388
...prev,
8489
{
85-
text: `✓ Platform set to ${platform} (${resolution})`,
90+
text: `✓ Orchard set to ${platform} (${resolution})`,
8691
delay: TIMING.INSTANT,
8792
type: "success",
8893
},
@@ -131,7 +136,7 @@ export const useTerminalMessages = () => {
131136
setMessages((prev) => [
132137
...prev,
133138
{
134-
text: "Starting video conversion...",
139+
text: "🍏 Pressing...",
135140
delay: TIMING.BEAT,
136141
type: "info",
137142
},
@@ -142,12 +147,12 @@ export const useTerminalMessages = () => {
142147
setMessages((prev) => [
143148
...prev,
144149
{
145-
text: "✓ Video is now ready for App Preview upload!",
150+
text: "🧃 Fresh cider ready! Your video is App Store approved.",
146151
delay: TIMING.PAUSE, // Pause for effect
147152
type: "success",
148153
buttons: [
149-
{ text: "Download", action: "download", type: "rainbow" },
150-
{ text: "New Conversion", action: "restart" },
154+
{ text: "Bottle It", action: "download", type: "rainbow" },
155+
{ text: "Press Another", action: "restart" },
151156
],
152157
},
153158
]);
@@ -156,12 +161,12 @@ export const useTerminalMessages = () => {
156161
const addSupportMessage = useCallback(() => {
157162
setMessages([
158163
{
159-
text: "All done. Thank you & enjoy!",
164+
text: "🍎 All pressed. Thank you & enjoy your cider!",
160165
delay: TIMING.INSTANT,
161166
type: "info",
162167
buttons: [
163168
{ text: "Buy me a coffee", action: "bmc", type: "bmc" },
164-
{ text: "New Conversion", action: "restart" },
169+
{ text: "Press Another", action: "restart" },
165170
],
166171
},
167172
]);
@@ -171,7 +176,7 @@ export const useTerminalMessages = () => {
171176
setMessages((prev) => [
172177
...prev,
173178
{
174-
text: `⚠️ ${message}`,
179+
text: `🍂 Bruised apple: ${message}`,
175180
delay: TIMING.INSTANT,
176181
type: "error",
177182
},

0 commit comments

Comments
 (0)