feat(ui): apply Justine ink & parchment design system
- Map Justine tokens to shadcn CSS variables (--vibn-* aliases) - Switch fonts to Inter + Lora via next/font (IBM Plex Mono for code) - Base typography: body Inter, h1–h3 Lora; marketing hero + wordmark serif - Project shell and global chrome use semantic colors - Replace Outfit/Newsreader references across TSX inline styles Made-with: Cursor
This commit is contained in:
@@ -32,11 +32,11 @@ const HOSTING_OPTIONS = [
|
||||
function MarkdownRenderer({ md }: { md: string }) {
|
||||
const lines = md.split('\n');
|
||||
return (
|
||||
<div style={{ fontFamily: "Outfit, sans-serif", fontSize: "0.85rem", color: "#1a1a1a", lineHeight: 1.7 }}>
|
||||
<div style={{ fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem", color: "#1a1a1a", lineHeight: 1.7 }}>
|
||||
{lines.map((line, i) => {
|
||||
if (line.startsWith('## ')) return <h2 key={i} style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 500, margin: "24px 0 10px", color: "#1a1a1a" }}>{line.slice(3)}</h2>;
|
||||
if (line.startsWith('## ')) return <h2 key={i} style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 500, margin: "24px 0 10px", color: "#1a1a1a" }}>{line.slice(3)}</h2>;
|
||||
if (line.startsWith('### ')) return <h3 key={i} style={{ fontSize: "0.88rem", fontWeight: 700, margin: "18px 0 6px", color: "#1a1a1a" }}>{line.slice(4)}</h3>;
|
||||
if (line.startsWith('# ')) return <h1 key={i} style={{ fontFamily: "Newsreader, serif", fontSize: "1.5rem", fontWeight: 400, margin: "0 0 16px", color: "#1a1a1a" }}>{line.slice(2)}</h1>;
|
||||
if (line.startsWith('# ')) return <h1 key={i} style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.5rem", fontWeight: 400, margin: "0 0 16px", color: "#1a1a1a" }}>{line.slice(2)}</h1>;
|
||||
if (line.match(/^- \[ \] /)) return (
|
||||
<div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 8, marginBottom: 5 }}>
|
||||
<input type="checkbox" style={{ marginTop: 3, accentColor: "#1a1a1a" }} />
|
||||
@@ -157,9 +157,9 @@ export function MigrateMain({
|
||||
const canProceed = repoUrl.trim().startsWith("http") || liveUrl.trim().startsWith("http");
|
||||
return (
|
||||
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
||||
<div style={{ width: "100%", maxWidth: 540, fontFamily: "Outfit, sans-serif" }}>
|
||||
<div style={{ width: "100%", maxWidth: 540, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||
<div style={{ marginBottom: 28 }}>
|
||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||
Tell us about your product
|
||||
</h2>
|
||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
||||
@@ -176,7 +176,7 @@ export function MigrateMain({
|
||||
</label>
|
||||
<input type="text" value={repoUrl} onChange={e => setRepoUrl(e.target.value)}
|
||||
placeholder="https://github.com/yourorg/your-repo"
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "Outfit, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")} autoFocus
|
||||
/>
|
||||
@@ -185,7 +185,7 @@ export function MigrateMain({
|
||||
</label>
|
||||
<input type="text" value={liveUrl} onChange={e => setLiveUrl(e.target.value)}
|
||||
placeholder="https://yourproduct.com"
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "Outfit, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")}
|
||||
/>
|
||||
@@ -193,7 +193,7 @@ export function MigrateMain({
|
||||
Current hosting provider
|
||||
</label>
|
||||
<select value={hosting} onChange={e => setHosting(e.target.value)}
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 20, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.88rem", fontFamily: "Outfit, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90", outline: "none", boxSizing: "border-box", appearance: "none" }}
|
||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 20, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.88rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90", outline: "none", boxSizing: "border-box", appearance: "none" }}
|
||||
>
|
||||
{HOSTING_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
|
||||
</select>
|
||||
@@ -201,7 +201,7 @@ export function MigrateMain({
|
||||
<strong style={{ color: "#4a2a5a" }}>Non-destructive.</strong> Your existing product stays live throughout. Atlas duplicates, never deletes.
|
||||
</div>
|
||||
<button onClick={startAudit} disabled={!canProceed}
|
||||
style={{ width: "100%", padding: "13px", borderRadius: 8, border: "none", background: canProceed ? "#1a1a1a" : "#e0dcd4", color: canProceed ? "#fff" : "#b5b0a6", fontSize: "0.9rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: canProceed ? "pointer" : "not-allowed" }}
|
||||
style={{ width: "100%", padding: "13px", borderRadius: 8, border: "none", background: canProceed ? "#1a1a1a" : "#e0dcd4", color: canProceed ? "#fff" : "#b5b0a6", fontSize: "0.9rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: canProceed ? "pointer" : "not-allowed" }}
|
||||
>
|
||||
Start audit →
|
||||
</button>
|
||||
@@ -220,7 +220,7 @@ export function MigrateMain({
|
||||
];
|
||||
const currentIdx = steps.findIndex(s => s.key === progressStep);
|
||||
return (
|
||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||
<div style={{ textAlign: "center", maxWidth: 400 }}>
|
||||
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 24px" }} />
|
||||
<style>{`@keyframes vibn-mig-spin { to { transform:rotate(360deg); } }`}</style>
|
||||
@@ -250,10 +250,10 @@ export function MigrateMain({
|
||||
const rows = (analysisResult?.rows as Array<{ category: string; item: string; status: string; detail?: string }>) ?? [];
|
||||
const summary = (analysisResult?.summary as string) ?? '';
|
||||
return (
|
||||
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "Outfit, sans-serif" }}>
|
||||
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Audit complete</h2>
|
||||
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Audit complete</h2>
|
||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{summary || `${projectName} — review your current infrastructure below.`}</p>
|
||||
</div>
|
||||
|
||||
@@ -286,7 +286,7 @@ export function MigrateMain({
|
||||
<div style={{ fontSize: "0.75rem", color: "#8a8478" }}>Atlas will generate a phased migration doc with Mirror, Validate, Cutover, and Decommission phases.</div>
|
||||
</div>
|
||||
<button onClick={startPlanning}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#fff", color: "#1a1a1a", fontSize: "0.85rem", fontWeight: 700, fontFamily: "Outfit, sans-serif", cursor: "pointer", flexShrink: 0 }}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#fff", color: "#1a1a1a", fontSize: "0.85rem", fontWeight: 700, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer", flexShrink: 0 }}
|
||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||||
>
|
||||
@@ -301,7 +301,7 @@ export function MigrateMain({
|
||||
// ── Stage: planning ───────────────────────────────────────────────────────
|
||||
if (stage === "planning") {
|
||||
return (
|
||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||
<div style={{ textAlign: "center" }}>
|
||||
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 20px" }} />
|
||||
<h3 style={{ fontSize: "1.05rem", fontWeight: 600, color: "#1a1a1a", margin: "0 0 6px" }}>Generating migration plan…</h3>
|
||||
@@ -313,7 +313,7 @@ export function MigrateMain({
|
||||
|
||||
// ── Stage: plan ───────────────────────────────────────────────────────────
|
||||
return (
|
||||
<div style={{ height: "100%", overflow: "auto", fontFamily: "Outfit, sans-serif" }}>
|
||||
<div style={{ height: "100%", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||
{/* Non-destructive banner */}
|
||||
<div style={{ background: "#4a2a5a12", borderBottom: "1px solid #4a2a5a30", padding: "12px 32px", display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
|
||||
<span style={{ fontSize: "1rem" }}>🛡️</span>
|
||||
@@ -326,7 +326,7 @@ export function MigrateMain({
|
||||
<div style={{ padding: "32px 40px" }}>
|
||||
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
||||
<div style={{ marginBottom: 28 }}>
|
||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Migration Plan</h2>
|
||||
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Migration Plan</h2>
|
||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{projectName} — four phased migration with rollback plan</p>
|
||||
</div>
|
||||
<div style={{ background: "#fff", borderRadius: 12, border: "1px solid #e8e4dc", padding: "28px 32px" }}>
|
||||
@@ -335,13 +335,13 @@ export function MigrateMain({
|
||||
<div style={{ marginTop: 20, display: "flex", gap: 10 }}>
|
||||
<button
|
||||
onClick={() => router.push(`/${workspace}/project/${projectId}/design`)}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.85rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: "pointer" }}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.85rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer" }}
|
||||
>
|
||||
Go to Design →
|
||||
</button>
|
||||
<button
|
||||
onClick={() => window.print()}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "1px solid #e0dcd4", background: "#fff", color: "#6b6560", fontSize: "0.85rem", fontWeight: 500, fontFamily: "Outfit, sans-serif", cursor: "pointer" }}
|
||||
style={{ padding: "11px 22px", borderRadius: 8, border: "1px solid #e0dcd4", background: "#fff", color: "#6b6560", fontSize: "0.85rem", fontWeight: 500, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer" }}
|
||||
>
|
||||
Print / Export
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user