pramudya-yb commited on
Commit
7bcfa1f
·
1 Parent(s): 26ef438

Minimalize landing page and remove rogasper

Browse files
README.md CHANGED
@@ -1,4 +1,4 @@
1
- ---
2
  title: Pram API
3
  emoji: 🚀
4
  colorFrom: green
@@ -282,8 +282,8 @@ For AI-related changes, see the **AI Generation Context** section in `AGENTS.md`
282
 
283
  If you find Pram helpful and want to support its ongoing development, consider buying the creator a coffee! Your support helps cover API and hosting costs. ☕
284
 
285
- - **[Saweria](https://saweria.co/rogasper)** (Indonesian supporters)
286
- - **[Ko-fi](https://ko-fi.com/rogasper)** (International)
287
 
288
  ## License
289
 
@@ -296,3 +296,4 @@ If you run a modified version as a network service, you must make the correspond
296
  <p align="center">
297
  Built with Bun, React, Hono, and tRPC.
298
  </p>
 
 
1
+ ---
2
  title: Pram API
3
  emoji: 🚀
4
  colorFrom: green
 
282
 
283
  If you find Pram helpful and want to support its ongoing development, consider buying the creator a coffee! Your support helps cover API and hosting costs. ☕
284
 
285
+ - **[Saweria](https://saweria.co/pram)** (Indonesian supporters)
286
+ - **[Ko-fi](https://ko-fi.com/pram)** (International)
287
 
288
  ## License
289
 
 
296
  <p align="center">
297
  Built with Bun, React, Hono, and tRPC.
298
  </p>
299
+
apps/server/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { trpcServer } from "@hono/trpc-server";
2
  import { createContext } from "@pram/api/context";
3
  import { appRouter } from "@pram/api/routers/index";
4
  import { checkRateLimitAllowed } from "@pram/api/lib/rate-limit";
@@ -73,7 +73,7 @@ app.use(
73
  );
74
 
75
  app.get("/sitemap.xml", (c) => {
76
- const baseUrl = "https://pram.rogasper.com";
77
  const urls = [
78
  { loc: `${baseUrl}/`, changefreq: "weekly", priority: "1.0" },
79
  ];
@@ -101,3 +101,4 @@ export default {
101
  hostname: "0.0.0.0",
102
  fetch: app.fetch,
103
  };
 
 
1
+ import { trpcServer } from "@hono/trpc-server";
2
  import { createContext } from "@pram/api/context";
3
  import { appRouter } from "@pram/api/routers/index";
4
  import { checkRateLimitAllowed } from "@pram/api/lib/rate-limit";
 
73
  );
74
 
75
  app.get("/sitemap.xml", (c) => {
76
+ const baseUrl = "https://pram-app.vercel.app";
77
  const urls = [
78
  { loc: `${baseUrl}/`, changefreq: "weekly", priority: "1.0" },
79
  ];
 
101
  hostname: "0.0.0.0",
102
  fetch: app.fetch,
103
  };
104
+
apps/web/index.html CHANGED
@@ -1,4 +1,4 @@
1
- <!doctype html>
2
  <html lang="id">
3
  <head>
4
  <meta charset="UTF-8" />
@@ -7,12 +7,12 @@
7
  <meta name="theme-color" content="#0c0c0c" />
8
  <meta property="og:title" content="Pram — AI-Powered Exam Practice Platform" />
9
  <meta property="og:description" content="Generate AI-powered practice questions for JLPT, TOPIK, TOAFL, and more. Practice smarter with adaptive test preparation." />
10
- <meta property="og:url" content="https://pram.rogasper.com/" />
11
  <meta property="og:site_name" content="Pram" />
12
  <meta property="og:locale" content="id_ID" />
13
  <meta property="og:type" content="website" />
14
- <meta property="og:image" content="https://pram.rogasper.com/opengraph-image.png" />
15
- <meta property="og:image:secure_url" content="https://pram.rogasper.com/opengraph-image.png" />
16
  <meta property="og:image:type" content="image/png" />
17
  <meta property="og:image:width" content="1200" />
18
  <meta property="og:image:height" content="630" />
@@ -20,13 +20,13 @@
20
  <meta name="twitter:card" content="summary_large_image" />
21
  <meta name="twitter:title" content="Pram — AI-Powered Exam Practice Platform" />
22
  <meta name="twitter:description" content="Generate AI-powered practice questions for JLPT, TOPIK, TOAFL, and more. Practice smarter with adaptive test preparation." />
23
- <meta name="twitter:image" content="https://pram.rogasper.com/twitter-image.jpg" />
24
  <meta name="twitter:image:alt" content="Pram — platform latihan ujian bahasa dengan AI Generator dan simulasi tes" />
25
  <meta name="twitter:image:type" content="image/jpeg" />
26
  <meta name="twitter:image:width" content="1200" />
27
  <meta name="twitter:image:height" content="630" />
28
  <meta name="robots" content="index, follow" />
29
- <link rel="canonical" href="https://pram.rogasper.com/" />
30
  <link rel="icon" href="/favicon.ico" sizes="48x48" />
31
  <link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" />
32
  <title>Pram — AI-Powered Exam Practice Platform</title>
@@ -37,3 +37,4 @@
37
  <script type="module" src="/src/main.tsx"></script>
38
  </body>
39
  </html>
 
 
1
+ <!doctype html>
2
  <html lang="id">
3
  <head>
4
  <meta charset="UTF-8" />
 
7
  <meta name="theme-color" content="#0c0c0c" />
8
  <meta property="og:title" content="Pram — AI-Powered Exam Practice Platform" />
9
  <meta property="og:description" content="Generate AI-powered practice questions for JLPT, TOPIK, TOAFL, and more. Practice smarter with adaptive test preparation." />
10
+ <meta property="og:url" content="https://pram-app.vercel.app/" />
11
  <meta property="og:site_name" content="Pram" />
12
  <meta property="og:locale" content="id_ID" />
13
  <meta property="og:type" content="website" />
14
+ <meta property="og:image" content="https://pram-app.vercel.app/opengraph-image.png" />
15
+ <meta property="og:image:secure_url" content="https://pram-app.vercel.app/opengraph-image.png" />
16
  <meta property="og:image:type" content="image/png" />
17
  <meta property="og:image:width" content="1200" />
18
  <meta property="og:image:height" content="630" />
 
20
  <meta name="twitter:card" content="summary_large_image" />
21
  <meta name="twitter:title" content="Pram — AI-Powered Exam Practice Platform" />
22
  <meta name="twitter:description" content="Generate AI-powered practice questions for JLPT, TOPIK, TOAFL, and more. Practice smarter with adaptive test preparation." />
23
+ <meta name="twitter:image" content="https://pram-app.vercel.app/twitter-image.jpg" />
24
  <meta name="twitter:image:alt" content="Pram — platform latihan ujian bahasa dengan AI Generator dan simulasi tes" />
25
  <meta name="twitter:image:type" content="image/jpeg" />
26
  <meta name="twitter:image:width" content="1200" />
27
  <meta name="twitter:image:height" content="630" />
28
  <meta name="robots" content="index, follow" />
29
+ <link rel="canonical" href="https://pram-app.vercel.app/" />
30
  <link rel="icon" href="/favicon.ico" sizes="48x48" />
31
  <link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" />
32
  <title>Pram — AI-Powered Exam Practice Platform</title>
 
37
  <script type="module" src="/src/main.tsx"></script>
38
  </body>
39
  </html>
40
+
apps/web/public/robots.txt CHANGED
@@ -1,3 +1,4 @@
1
  User-agent: *
2
  Allow: /
3
- Sitemap: https://pram.rogasper.com/sitemap.xml
 
 
1
  User-agent: *
2
  Allow: /
3
+ Sitemap: https://pram-app.vercel.app/sitemap.xml
4
+
apps/web/public/sitemap.xml CHANGED
@@ -1,28 +1,29 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
  <url>
4
- <loc>https://pram.rogasper.com/</loc>
5
  <changefreq>weekly</changefreq>
6
  <priority>1.0</priority>
7
  </url>
8
  <url>
9
- <loc>https://pram.rogasper.com/login</loc>
10
  <changefreq>monthly</changefreq>
11
  <priority>0.5</priority>
12
  </url>
13
  <url>
14
- <loc>https://pram.rogasper.com/bank</loc>
15
  <changefreq>weekly</changefreq>
16
  <priority>0.8</priority>
17
  </url>
18
  <url>
19
- <loc>https://pram.rogasper.com/packages</loc>
20
  <changefreq>weekly</changefreq>
21
  <priority>0.8</priority>
22
  </url>
23
  <url>
24
- <loc>https://pram.rogasper.com/leaderboard</loc>
25
  <changefreq>daily</changefreq>
26
  <priority>0.6</priority>
27
  </url>
28
  </urlset>
 
 
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
  <url>
4
+ <loc>https://pram-app.vercel.app/</loc>
5
  <changefreq>weekly</changefreq>
6
  <priority>1.0</priority>
7
  </url>
8
  <url>
9
+ <loc>https://pram-app.vercel.app/login</loc>
10
  <changefreq>monthly</changefreq>
11
  <priority>0.5</priority>
12
  </url>
13
  <url>
14
+ <loc>https://pram-app.vercel.app/bank</loc>
15
  <changefreq>weekly</changefreq>
16
  <priority>0.8</priority>
17
  </url>
18
  <url>
19
+ <loc>https://pram-app.vercel.app/packages</loc>
20
  <changefreq>weekly</changefreq>
21
  <priority>0.8</priority>
22
  </url>
23
  <url>
24
+ <loc>https://pram-app.vercel.app/leaderboard</loc>
25
  <changefreq>daily</changefreq>
26
  <priority>0.6</priority>
27
  </url>
28
  </urlset>
29
+
apps/web/src/components/DonationModal.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@pram/ui/components/dialog";
2
  import { MaterialIcon } from "@/components/ui/MaterialIcon";
3
 
4
  export function DonationModal({
@@ -28,7 +28,7 @@ export function DonationModal({
28
  </DialogHeader>
29
  <div className="flex flex-col gap-3 mt-6">
30
  <a
31
- href="https://saweria.co/rogasper"
32
  target="_blank"
33
  rel="noopener noreferrer"
34
  className="w-full flex items-center justify-center gap-2 py-3.5 px-4 rounded-[var(--radius-lg)] font-bold transition-all bg-[#F3B63A] text-black hover:brightness-95 clay-shadow clay-hover"
@@ -37,7 +37,7 @@ export function DonationModal({
37
  Support via Saweria
38
  </a>
39
  <a
40
- href="https://ko-fi.com/rogasper"
41
  target="_blank"
42
  rel="noopener noreferrer"
43
  className="w-full flex items-center justify-center gap-2 py-3.5 px-4 rounded-[var(--radius-lg)] font-bold transition-all bg-[#13C3FF] text-white hover:brightness-95 clay-shadow clay-hover"
@@ -56,3 +56,4 @@ export function DonationModal({
56
  </Dialog>
57
  );
58
  }
 
 
1
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@pram/ui/components/dialog";
2
  import { MaterialIcon } from "@/components/ui/MaterialIcon";
3
 
4
  export function DonationModal({
 
28
  </DialogHeader>
29
  <div className="flex flex-col gap-3 mt-6">
30
  <a
31
+ href="https://saweria.co/pram"
32
  target="_blank"
33
  rel="noopener noreferrer"
34
  className="w-full flex items-center justify-center gap-2 py-3.5 px-4 rounded-[var(--radius-lg)] font-bold transition-all bg-[#F3B63A] text-black hover:brightness-95 clay-shadow clay-hover"
 
37
  Support via Saweria
38
  </a>
39
  <a
40
+ href="https://ko-fi.com/pram"
41
  target="_blank"
42
  rel="noopener noreferrer"
43
  className="w-full flex items-center justify-center gap-2 py-3.5 px-4 rounded-[var(--radius-lg)] font-bold transition-all bg-[#13C3FF] text-white hover:brightness-95 clay-shadow clay-hover"
 
56
  </Dialog>
57
  );
58
  }
59
+
apps/web/src/components/routes/LandingPage.tsx CHANGED
@@ -59,16 +59,6 @@ export function LandingPage() {
59
  <MaterialIcon name="forum" className="text-xl" />
60
  <span className="font-semibold text-base">Komunitas</span>
61
  </button>
62
- <a href="https://saweria.co/rogasper" target="_blank" rel="noopener noreferrer" className="text-[var(--warm-charcoal)] hover:text-[var(--pomegranate-400)] transition-colors p-2 hidden md:flex items-center gap-2" aria-label="Support via Saweria">
63
- <MaterialIcon name="favorite" className="text-xl" />
64
- <span className="font-semibold text-base">Support</span>
65
- </a>
66
- <a href="https://github.com/rogasper/pram-bahasa" target="_blank" rel="noopener noreferrer" className="text-[var(--warm-charcoal)] hover:text-[var(--clay-black)] transition-colors p-2 hidden sm:flex items-center gap-2" aria-label="GitHub Repository">
67
- <svg viewBox="0 0 24 24" className="w-6 h-6 fill-current" aria-hidden="true">
68
- <path fillRule="evenodd" clipRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" />
69
- </svg>
70
- <span className="font-semibold text-base">Star us</span>
71
- </a>
72
  <div className="w-px h-6 bg-[var(--oat-border)] hidden sm:block mx-2"></div>
73
  <Link to="/login">
74
  <Button variant="ghost" className="text-[var(--clay-black)] font-semibold hover:bg-[var(--oat-light)] rounded-[12px] text-lg px-4 sm:px-6 h-12">
@@ -106,14 +96,6 @@ export function LandingPage() {
106
  Mulai Latihan Sekarang
107
  </Button>
108
  </Link>
109
- <a href="https://github.com/rogasper/pram-bahasa" target="_blank" rel="noopener noreferrer" className="w-full sm:w-auto">
110
- <Button variant="ghost" className="w-full sm:w-auto text-[var(--clay-black)] rounded-[24px] h-[64px] px-8 text-xl font-semibold hover:bg-[var(--oat-light)] border-2 border-transparent flex items-center gap-3">
111
- <svg viewBox="0 0 24 24" className="w-6 h-6 fill-current" aria-hidden="true">
112
- <path fillRule="evenodd" clipRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" />
113
- </svg>
114
- Lihat di GitHub
115
- </Button>
116
- </a>
117
  </div>
118
  </div>
119
 
@@ -139,184 +121,7 @@ export function LandingPage() {
139
  </div>
140
  </section>
141
 
142
- {/* VIDEO DEMO SECTION - DYNAMIC ZIGZAG */}
143
- <section id="demo" className="w-full bg-[var(--warm-cream)] py-20 pb-32 relative overflow-hidden">
144
- {/* Decorative background elements */}
145
- <div className="absolute top-40 -left-64 w-[500px] h-[500px] bg-[var(--matcha-300)]/30 rounded-full blur-3xl pointer-events-none"></div>
146
- <div className="absolute bottom-40 -right-64 w-[600px] h-[600px] bg-[var(--slushie-500)]/20 rounded-full blur-3xl pointer-events-none"></div>
147
-
148
- <div className="max-w-7xl mx-auto px-6 md:px-12 lg:px-16 relative z-10">
149
- <div className="text-center max-w-3xl mx-auto mb-24 space-y-6">
150
- <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-[var(--ube-300)]/30 border-2 border-[var(--ube-300)] text-[var(--ube-800)] uppercase-label shadow-sm">
151
- <MaterialIcon name="play_circle" className="text-sm" />
152
- <span>Lihat Aksinya</span>
153
- </div>
154
- <h2 className="text-[50px] md:text-[60px] font-headline font-semibold text-[var(--clay-black)] tracking-[-2.4px] leading-tight drop-shadow-sm">
155
- Pengalaman Belajar Generasi Baru
156
- </h2>
157
- </div>
158
-
159
- <div className="space-y-32">
160
- {/* Feature 1: Hero Showcase - Generate AI */}
161
- <div className="flex flex-col items-center text-center pb-8 pt-4">
162
- <div className="max-w-3xl space-y-5 mb-10">
163
- <div className="inline-block px-4 py-1.5 rounded-full bg-[var(--ube-300)]/20 border-2 border-[var(--ube-300)]/50 text-[var(--ube-800)] text-sm font-bold tracking-wide uppercase-label mb-2">✨ Fitur Unggulan</div>
164
- <h3 className="text-[36px] md:text-[45px] lg:text-[55px] font-headline font-semibold text-[var(--clay-black)] leading-[1.1] tracking-[-1.5px]">
165
- Generate Soal <br className="hidden sm:block md:hidden" /> <span className="text-[var(--ube-800)]">Agentic AI</span>
166
- </h3>
167
- <p className="text-lg md:text-xl text-[var(--warm-charcoal)] leading-relaxed max-w-2xl mx-auto">
168
- Masukkan teks bacaan bahasa asing, dan biarkan sistem <i>Multi-step Agentic Pipeline</i> kami (Validasi → Generasi → Self-check) menyusun paket soal bermutu secara otomatis.
169
- </p>
170
- </div>
171
-
172
- <div className="w-full relative group max-w-5xl mx-auto">
173
- <div className="absolute inset-0 bg-gradient-to-tr from-[var(--ube-400)] via-[var(--matcha-300)] to-[var(--lemon-400)] rounded-[48px] transform rotate-1 group-hover:rotate-2 transition-transform duration-700 opacity-60 blur-xl"></div>
174
- <div className="absolute inset-0 bg-gradient-to-tr from-[var(--ube-400)] via-[var(--matcha-300)] to-[var(--lemon-400)] rounded-[48px] transform rotate-1 group-hover:rotate-2 transition-transform duration-700"></div>
175
- <div className="relative rounded-[48px] overflow-hidden border-[6px] border-[var(--pure-white)] shadow-[0_30px_80px_rgba(0,0,0,0.2)] bg-[var(--oat-light)] transform transition-transform duration-700 group-hover:-translate-y-2">
176
- <video
177
- className="w-full aspect-video object-cover"
178
- autoPlay
179
- muted
180
- loop
181
- playsInline
182
- >
183
- <source src="/generate%20soal.mp4" type="video/mp4" />
184
- Browser Anda tidak mendukung tag video.
185
- </video>
186
- </div>
187
-
188
- {/* Floating badge 1 */}
189
- <div className="absolute -bottom-8 right-4 md:-right-8 bg-[var(--pure-white)] border-2 border-[var(--oat-border)] p-4 md:p-5 rounded-[24px] md:rounded-[28px] shadow-2xl clay-hover transform -rotate-3 z-20 flex items-center gap-3 md:gap-4">
190
- <div className="w-12 h-12 md:w-14 md:h-14 rounded-full bg-[var(--ube-300)] flex items-center justify-center">
191
- <MaterialIcon name="smart_toy" className="text-2xl md:text-3xl text-[var(--ube-800)]" />
192
- </div>
193
- <div className="text-left">
194
- <p className="text-base md:text-lg font-bold text-[var(--clay-black)] leading-tight">Agentic Pipeline</p>
195
- <p className="text-xs md:text-sm text-[var(--warm-charcoal)]">Generasi & Self-Check</p>
196
- </div>
197
- </div>
198
-
199
- {/* Floating badge 2 */}
200
- <div className="absolute -top-8 left-4 md:-left-8 bg-[var(--pure-white)] border-2 border-[var(--oat-border)] p-4 rounded-[24px] shadow-2xl clay-hover transform rotate-3 z-20 flex items-center gap-3 hidden md:flex">
201
- <div className="w-12 h-12 rounded-full bg-[var(--lemon-400)] flex items-center justify-center">
202
- <MaterialIcon name="verified" className="text-2xl text-[var(--lemon-800)]" />
203
- </div>
204
- <div className="text-left">
205
- <p className="font-bold text-[var(--clay-black)] leading-tight">Kualitas Tinggi</p>
206
- <p className="text-xs text-[var(--warm-charcoal)]">Evaluasi Otomatis</p>
207
- </div>
208
- </div>
209
- </div>
210
- </div>
211
-
212
- {/* Feature 2: Zigzag Right - Manajemen Paket */}
213
- <div className="flex flex-col lg:flex-row-reverse items-center gap-12 lg:gap-20">
214
- <div className="flex-1 w-full lg:w-1/2 relative group">
215
- <div className="absolute inset-0 bg-gradient-to-tr from-[var(--matcha-400)] to-[var(--lemon-400)] rounded-[40px] transform -rotate-3 group-hover:-rotate-6 transition-transform duration-700"></div>
216
- <div className="relative rounded-[40px] overflow-hidden border-4 border-[var(--pure-white)] shadow-[0_20px_60px_rgba(0,0,0,0.15)] transform transition-transform duration-700 group-hover:-translate-y-2 bg-[var(--oat-light)]">
217
- <video
218
- className="w-full aspect-video object-cover"
219
- autoPlay
220
- muted
221
- loop
222
- playsInline
223
- >
224
- <source src="/paket%20soal.mp4" type="video/mp4" />
225
- Browser Anda tidak mendukung tag video.
226
- </video>
227
- </div>
228
-
229
- {/* Floating badge */}
230
- <div className="absolute -top-6 -left-6 md:-left-10 bg-[var(--pure-white)] border-2 border-[var(--oat-border)] p-4 rounded-[24px] shadow-xl clay-hover transform rotate-6 z-20 flex items-center gap-3">
231
- <div className="w-12 h-12 rounded-full bg-[var(--matcha-300)] flex items-center justify-center">
232
- <MaterialIcon name="source" className="text-2xl text-[var(--matcha-800)]" />
233
- </div>
234
- <div>
235
- <p className="font-bold text-[var(--clay-black)] leading-tight">Bank Soal</p>
236
- <p className="text-xs text-[var(--warm-charcoal)]">Koleksi Lengkap</p>
237
- </div>
238
- </div>
239
- </div>
240
-
241
- <div className="flex-1 w-full lg:w-1/2 space-y-6">
242
- <h3 className="text-[40px] lg:text-[50px] font-headline font-semibold text-[var(--clay-black)] leading-[1.1] tracking-[-1.5px]">
243
- Kustomisasi <br/> <span className="text-[var(--matcha-600)]">Paket Belajar</span>
244
- </h3>
245
- <p className="text-xl text-[var(--warm-charcoal)] leading-relaxed">
246
- Eksplorasi Bank Soal untuk merakit paket latihan Anda sendiri. Publikasikan paket soal buatan Anda, atau gunakan paket pilihan dari daftar Editor's Pick.
247
- </p>
248
- <ul className="space-y-4 pt-4">
249
- <li className="flex items-center gap-3">
250
- <div className="w-8 h-8 rounded-full bg-[var(--matcha-300)]/50 flex items-center justify-center">
251
- <MaterialIcon name="check" className="text-[var(--matcha-800)]" />
252
- </div>
253
- <span className="text-lg font-medium text-[var(--clay-black)]">Bank Soal Terintegrasi</span>
254
- </li>
255
- <li className="flex items-center gap-3">
256
- <div className="w-8 h-8 rounded-full bg-[var(--matcha-300)]/50 flex items-center justify-center">
257
- <MaterialIcon name="check" className="text-[var(--matcha-800)]" />
258
- </div>
259
- <span className="text-lg font-medium text-[var(--clay-black)]">Sistem Publikasi Paket</span>
260
- </li>
261
- </ul>
262
- </div>
263
- </div>
264
-
265
- {/* Feature 3: Zigzag Left - Simulasi */}
266
- <div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-20">
267
- <div className="flex-1 w-full lg:w-1/2 relative group">
268
- <div className="absolute inset-0 bg-gradient-to-tr from-[var(--slushie-500)] to-[var(--ube-400)] rounded-[40px] transform rotate-3 group-hover:rotate-6 transition-transform duration-700"></div>
269
- <div className="relative rounded-[40px] overflow-hidden border-4 border-[var(--pure-white)] shadow-[0_20px_60px_rgba(0,0,0,0.15)] transform transition-transform duration-700 group-hover:-translate-y-2 bg-[var(--oat-light)]">
270
- <video
271
- className="w-full aspect-video object-cover"
272
- autoPlay
273
- muted
274
- loop
275
- playsInline
276
- >
277
- <source src="/attempt%20exam.mp4" type="video/mp4" />
278
- Browser Anda tidak mendukung tag video.
279
- </video>
280
- </div>
281
 
282
- {/* Floating badge */}
283
- <div className="absolute -bottom-6 -right-6 md:-right-10 bg-[var(--pure-white)] border-2 border-[var(--oat-border)] p-4 rounded-[24px] shadow-xl clay-hover transform -rotate-6 z-20 flex items-center gap-3">
284
- <div className="w-12 h-12 rounded-full bg-[var(--slushie-500)] flex items-center justify-center">
285
- <MaterialIcon name="timer" className="text-2xl text-[var(--clay-black)]" />
286
- </div>
287
- <div>
288
- <p className="font-bold text-[var(--clay-black)] leading-tight">Anti-Curang</p>
289
- <p className="text-xs text-[var(--warm-charcoal)]">Validasi Waktu</p>
290
- </div>
291
- </div>
292
- </div>
293
-
294
- <div className="flex-1 w-full lg:w-1/2 space-y-6">
295
- <h3 className="text-[40px] lg:text-[50px] font-headline font-semibold text-[var(--clay-black)] leading-[1.1] tracking-[-1.5px]">
296
- Simulasi Ujian <br/> <span className="text-[var(--slushie-600)]">Fokus Penuh</span>
297
- </h3>
298
- <p className="text-xl text-[var(--warm-charcoal)] leading-relaxed">
299
- Kerjakan latihan dengan antarmuka ujian sesungguhnya. Selesaikan tes dengan sistem timer yang tervalidasi secara akurat, dan dapatkan kalkulasi skor serta akurasi secara instan.
300
- </p>
301
- <ul className="space-y-4 pt-4">
302
- <li className="flex items-center gap-3">
303
- <div className="w-8 h-8 rounded-full bg-[var(--slushie-500)]/30 flex items-center justify-center">
304
- <MaterialIcon name="check" className="text-[var(--clay-black)]" />
305
- </div>
306
- <span className="text-lg font-medium text-[var(--clay-black)]">Sistem Timer Tervalidasi</span>
307
- </li>
308
- <li className="flex items-center gap-3">
309
- <div className="w-8 h-8 rounded-full bg-[var(--slushie-500)]/30 flex items-center justify-center">
310
- <MaterialIcon name="check" className="text-[var(--clay-black)]" />
311
- </div>
312
- <span className="text-lg font-medium text-[var(--clay-black)]">Kalkulasi Skor Otomatis</span>
313
- </li>
314
- </ul>
315
- </div>
316
- </div>
317
- </div>
318
- </div>
319
- </section>
320
 
321
  {/* Feature Cards Section */}
322
  <section id="features" className="w-full bg-[var(--pure-white)] py-32 border-y-2 border-dashed border-[var(--oat-border)]">
@@ -485,43 +290,6 @@ export function LandingPage() {
485
 
486
  {/* Footer */}
487
  <footer className="w-full bg-[var(--pure-white)] py-12 border-t-2 border-[var(--oat-border)] text-center relative z-30">
488
- <div className="flex flex-col items-center gap-4 mb-8">
489
- <p className="text-[var(--warm-charcoal)] font-semibold text-lg">Hubungi Kami</p>
490
- <div className="flex flex-wrap justify-center items-center gap-6 text-[var(--clay-black)]">
491
- <a href="mailto:admin@rogasper.com" className="flex items-center gap-2 hover:text-[var(--matcha-700)] transition-colors">
492
- <MaterialIcon name="mail" />
493
- <span className="font-semibold">admin@rogasper.com</span>
494
- </a>
495
- <a href="https://instagram.com/rogasper" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 hover:text-[var(--matcha-700)] transition-colors">
496
- <MaterialIcon name="photo_camera" />
497
- <span className="font-semibold">@rogasper</span>
498
- </a>
499
- <a href="https://github.com/rogasper/pram-bahasa" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 hover:text-[var(--matcha-700)] transition-colors">
500
- <MaterialIcon name="code" />
501
- <span className="font-semibold">GitHub</span>
502
- </a>
503
- <a href="https://saweria.co/rogasper" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 hover:text-[var(--pomegranate-400)] transition-colors">
504
- <MaterialIcon name="favorite" />
505
- <span className="font-semibold">Saweria</span>
506
- </a>
507
- <a href="https://ko-fi.com/rogasper" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 hover:text-[var(--pomegranate-400)] transition-colors">
508
- <MaterialIcon name="local_cafe" />
509
- <span className="font-semibold">Ko-fi</span>
510
- </a>
511
- <button
512
- type="button"
513
- onClick={() => setCommunityModalOpen(true)}
514
- className="flex items-center gap-2 hover:text-[#128C7E] transition-colors"
515
- >
516
- <MaterialIcon name="forum" />
517
- <span className="font-semibold">Komunitas WhatsApp</span>
518
- </button>
519
- <a href="https://rogasper.com" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2 hover:text-[var(--matcha-700)] transition-colors">
520
- <MaterialIcon name="language" />
521
- <span className="font-semibold">rogasper.com</span>
522
- </a>
523
- </div>
524
- </div>
525
  <p className="text-[var(--warm-charcoal)] font-semibold text-lg">
526
  &copy; {new Date().getFullYear()} Pram. Didesain dengan penuh kehangatan.
527
  </p>
 
59
  <MaterialIcon name="forum" className="text-xl" />
60
  <span className="font-semibold text-base">Komunitas</span>
61
  </button>
 
 
 
 
 
 
 
 
 
 
62
  <div className="w-px h-6 bg-[var(--oat-border)] hidden sm:block mx-2"></div>
63
  <Link to="/login">
64
  <Button variant="ghost" className="text-[var(--clay-black)] font-semibold hover:bg-[var(--oat-light)] rounded-[12px] text-lg px-4 sm:px-6 h-12">
 
96
  Mulai Latihan Sekarang
97
  </Button>
98
  </Link>
 
 
 
 
 
 
 
 
99
  </div>
100
  </div>
101
 
 
121
  </div>
122
  </section>
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  {/* Feature Cards Section */}
127
  <section id="features" className="w-full bg-[var(--pure-white)] py-32 border-y-2 border-dashed border-[var(--oat-border)]">
 
290
 
291
  {/* Footer */}
292
  <footer className="w-full bg-[var(--pure-white)] py-12 border-t-2 border-[var(--oat-border)] text-center relative z-30">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  <p className="text-[var(--warm-charcoal)] font-semibold text-lg">
294
  &copy; {new Date().getFullYear()} Pram. Didesain dengan penuh kehangatan.
295
  </p>
apps/web/src/lib/community-links.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type CommunityPlatform = "whatsapp" | "discord";
2
 
3
  export type CommunityChannel = {
4
  id: string;
@@ -43,8 +43,8 @@ export const COMMUNITY_CHANNELS: CommunityChannel[] = [
43
  {
44
  id: "learning-whatsapp",
45
  platform: "whatsapp",
46
- name: "Rogasper Learning",
47
- description: "Berbagi tips, trik, dan berita terbaru dari Rogasper Learning.",
48
  href: "https://chat.whatsapp.com/IrQOUGB3jhR7WnOoilCill",
49
  icon: "school",
50
  },
@@ -70,3 +70,4 @@ export function getCommunitySections() {
70
  channels: COMMUNITY_CHANNELS.filter((c) => c.platform === platform),
71
  })).filter((section) => section.channels.length > 0);
72
  }
 
 
1
+ export type CommunityPlatform = "whatsapp" | "discord";
2
 
3
  export type CommunityChannel = {
4
  id: string;
 
43
  {
44
  id: "learning-whatsapp",
45
  platform: "whatsapp",
46
+ name: "pram Learning",
47
+ description: "Berbagi tips, trik, dan berita terbaru dari pram Learning.",
48
  href: "https://chat.whatsapp.com/IrQOUGB3jhR7WnOoilCill",
49
  icon: "school",
50
  },
 
70
  channels: COMMUNITY_CHANNELS.filter((c) => c.platform === platform),
71
  })).filter((section) => section.channels.length > 0);
72
  }
73
+
apps/web/src/lib/site-seo.ts CHANGED
@@ -1,7 +1,7 @@
1
- export const SITE_URL = "https://pram.rogasper.com";
2
  export const SITE_NAME = "Pram";
3
 
4
- /** Match rogasper.com: separate OG (PNG) + Twitter (JPEG) assets for crawler compatibility. */
5
  export const OG_IMAGE_PATH = "/opengraph-image.png";
6
  export const TWITTER_IMAGE_PATH = "/twitter-image.jpg";
7
  /** @deprecated Use OG_IMAGE_PATH — kept for old links */
@@ -54,3 +54,4 @@ export function buildSocialMeta(input: SiteHeadInput = {}) {
54
  { name: "twitter:image:height", content: String(OG_IMAGE_HEIGHT) },
55
  ];
56
  }
 
 
1
+ export const SITE_URL = "https://pram-app.vercel.app";
2
  export const SITE_NAME = "Pram";
3
 
4
+ /** Match pram-app.vercel.app: separate OG (PNG) + Twitter (JPEG) assets for crawler compatibility. */
5
  export const OG_IMAGE_PATH = "/opengraph-image.png";
6
  export const TWITTER_IMAGE_PATH = "/twitter-image.jpg";
7
  /** @deprecated Use OG_IMAGE_PATH — kept for old links */
 
54
  { name: "twitter:image:height", content: String(OG_IMAGE_HEIGHT) },
55
  ];
56
  }
57
+
apps/web/src/routes/__root.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Toaster } from "@pram/ui/components/sonner";
2
  import type { QueryClient } from "@tanstack/react-query";
3
  import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
4
  import { HeadContent, Outlet, createRootRouteWithContext, useRouterState } from "@tanstack/react-router";
@@ -64,7 +64,7 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
64
  ],
65
  scripts: [
66
  ...(import.meta.env.PROD
67
- ? [{ src: "https://umami-analytic.rogasper.com/script.js", defer: true, "data-website-id": "67a18412-12c8-44ef-9cd3-e04238d37e9a" }]
68
  : []),
69
  {
70
  type: "application/ld+json",
@@ -132,3 +132,4 @@ function RootComponent() {
132
  </>
133
  );
134
  }
 
 
1
+ import { Toaster } from "@pram/ui/components/sonner";
2
  import type { QueryClient } from "@tanstack/react-query";
3
  import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
4
  import { HeadContent, Outlet, createRootRouteWithContext, useRouterState } from "@tanstack/react-router";
 
64
  ],
65
  scripts: [
66
  ...(import.meta.env.PROD
67
+ ? [{ src: "https://umami-analytic.pram-app.vercel.app/script.js", defer: true, "data-website-id": "67a18412-12c8-44ef-9cd3-e04238d37e9a" }]
68
  : []),
69
  {
70
  type: "application/ld+json",
 
132
  </>
133
  );
134
  }
135
+
apps/web/vite.config.ts CHANGED
@@ -1,4 +1,4 @@
1
- import tailwindcss from "@tailwindcss/vite";
2
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
3
  import react from "@vitejs/plugin-react";
4
  import { defineConfig } from "vite";
@@ -29,7 +29,7 @@ export default defineConfig({
29
  transformIndexHtml(html) {
30
  return html.replace(
31
  "</head>",
32
- '<script defer src="https://umami-analytic.rogasper.com/script.js" data-website-id="67a18412-12c8-44ef-9cd3-e04238d37e9a"></script></head>',
33
  );
34
  },
35
  apply: "build",
@@ -53,3 +53,4 @@ export default defineConfig({
53
  }),
54
  ],
55
  });
 
 
1
+ import tailwindcss from "@tailwindcss/vite";
2
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
3
  import react from "@vitejs/plugin-react";
4
  import { defineConfig } from "vite";
 
29
  transformIndexHtml(html) {
30
  return html.replace(
31
  "</head>",
32
+ '<script defer src="https://umami-analytic.pram-app.vercel.app/script.js" data-website-id="67a18412-12c8-44ef-9cd3-e04238d37e9a"></script></head>',
33
  );
34
  },
35
  apply: "build",
 
53
  }),
54
  ],
55
  });
56
+
scripts/compress-og-image.ts CHANGED
@@ -1,4 +1,4 @@
1
- /**
2
  * Build social preview images for Pram (Open Graph + Twitter).
3
  * Requires Bun >= 1.3.14 (Bun.Image API).
4
  *
@@ -53,7 +53,7 @@ async function main() {
53
  // Truecolor PNG — compatible with Meta/Twitter crawlers (no 8-bit palette).
54
  await base.png({ compressionLevel: 9, palette: false }).write(OPENGRAPH);
55
 
56
- // JPEG for twitter:image — matches rogasper.com pattern, very reliable on X/Threads.
57
  await requireBunImage(OPENGRAPH)
58
  .jpeg({ quality: 88, mozjpeg: true })
59
  .write(TWITTER);
@@ -71,3 +71,4 @@ main().catch((err) => {
71
  console.error(err);
72
  process.exit(1);
73
  });
 
 
1
+ /**
2
  * Build social preview images for Pram (Open Graph + Twitter).
3
  * Requires Bun >= 1.3.14 (Bun.Image API).
4
  *
 
53
  // Truecolor PNG — compatible with Meta/Twitter crawlers (no 8-bit palette).
54
  await base.png({ compressionLevel: 9, palette: false }).write(OPENGRAPH);
55
 
56
+ // JPEG for twitter:image — matches pram-app.vercel.app pattern, very reliable on X/Threads.
57
  await requireBunImage(OPENGRAPH)
58
  .jpeg({ quality: 88, mozjpeg: true })
59
  .write(TWITTER);
 
71
  console.error(err);
72
  process.exit(1);
73
  });
74
+