diff --git a/apps/apollo-vertex/app/(preview)/layout.tsx b/apps/apollo-vertex/app/(preview)/layout.tsx new file mode 100644 index 000000000..02b220198 --- /dev/null +++ b/apps/apollo-vertex/app/(preview)/layout.tsx @@ -0,0 +1,9 @@ +import type { ReactNode } from "react"; + +export default function PreviewLayout({ children }: { children: ReactNode }) { + return ( +
+ {children} +
+ ); +} diff --git a/apps/apollo-vertex/app/(preview)/preview/shell-minimal/loan-qc-dashboard.tsx b/apps/apollo-vertex/app/(preview)/preview/shell-minimal/loan-qc-dashboard.tsx new file mode 100644 index 000000000..153f51a03 --- /dev/null +++ b/apps/apollo-vertex/app/(preview)/preview/shell-minimal/loan-qc-dashboard.tsx @@ -0,0 +1,200 @@ +"use client"; + +import { + AlertTriangle, + CheckCircle, + Clock, + FileSearch, + ShieldCheck, + TrendingUp, + XCircle, +} from "lucide-react"; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +const kpis = [ + { label: "Loans Reviewed", value: "3,842", icon: FileSearch, change: "+18%" }, + { label: "Pending QC", value: "127", icon: Clock, change: "-8%" }, + { label: "Compliance Rate", value: "99.1%", icon: ShieldCheck, change: "+0.3%" }, + { label: "Defect Rate", value: "0.9%", icon: TrendingUp, change: "-0.2%" }, +]; + +const loans = [ + { id: "LN-8842", borrower: "Martinez Holdings LLC", amount: "$1,250,000", type: "Commercial", status: "Passed" as const, date: "Feb 25, 2026" }, + { id: "LN-8841", borrower: "Sarah Chen", amount: "$485,000", type: "Residential", status: "Flagged" as const, date: "Feb 25, 2026" }, + { id: "LN-8840", borrower: "Greenfield Dev Corp", amount: "$3,200,000", type: "Construction", status: "In Review" as const, date: "Feb 24, 2026" }, + { id: "LN-8839", borrower: "James & Linda Park", amount: "$320,000", type: "Residential", status: "Passed" as const, date: "Feb 24, 2026" }, + { id: "LN-8838", borrower: "NovaTech Industries", amount: "$890,000", type: "Commercial", status: "Failed" as const, date: "Feb 23, 2026" }, + { id: "LN-8837", borrower: "Riverside Properties", amount: "$2,100,000", type: "Commercial", status: "Passed" as const, date: "Feb 23, 2026" }, +]; + +const statusVariant: Record = { + Passed: "default", + "In Review": "secondary", + Failed: "destructive", + Flagged: "outline", +}; + +const statusIcon: Record = { + Passed: CheckCircle, + "In Review": Clock, + Failed: XCircle, + Flagged: AlertTriangle, +}; + +const complianceChecks = [ + { label: "Income Verification", pass: 98 }, + { label: "Credit Score Threshold", pass: 96 }, + { label: "Debt-to-Income Ratio", pass: 91 }, + { label: "Collateral Appraisal", pass: 87 }, + { label: "Document Completeness", pass: 94 }, +]; + +const recentFindings = [ + { text: "LN-8838 — missing employment verification letter", time: "1 hr ago", severity: "high" as const }, + { text: "LN-8841 — DTI ratio exceeds threshold (43.2%)", time: "2 hrs ago", severity: "medium" as const }, + { text: "Batch QC completed — 156 loans, 2 flagged", time: "4 hrs ago", severity: "low" as const }, + { text: "LN-8835 — appraisal gap identified ($12K)", time: "6 hrs ago", severity: "medium" as const }, +]; + +const severityColor: Record = { + high: "bg-destructive", + medium: "bg-warning", + low: "bg-primary", +}; + +export function LoanQcDashboard({ visible }: { visible: boolean }) { + if (!visible) return null; + + return ( +
+ {/* Header */} +
+

Loan Processing QC

+

+ Quality control and compliance monitoring for loan origination +

+
+ + {/* KPI Cards */} +
+ {kpis.map((kpi) => ( + + +
+ + {kpi.label} + + +
+
+ +
{kpi.value}
+

+ {kpi.change} from last week +

+
+
+ ))} +
+ + {/* Loans Table */} + + + Recent QC Reviews + + + + + + Loan ID + Borrower + Amount + Type + Status + Date + + + + {loans.map((loan) => { + const StatusIcon = statusIcon[loan.status]; + return ( + + {loan.id} + {loan.borrower} + {loan.amount} + {loan.type} + + + + {loan.status} + + + {loan.date} + + ); + })} + +
+
+
+ + {/* Bottom Row */} +
+ {/* Compliance Checks */} + + + Compliance Pass Rates + + +
+ {complianceChecks.map((check) => ( +
+
+ {check.label} + {check.pass}% +
+ +
+ ))} +
+
+
+ + {/* Recent Findings */} + + + Recent Findings + + +
+ {recentFindings.map((finding, i) => ( +
+
+
+

{finding.text}

+

{finding.time}

+
+
+ ))} +
+ + +
+
+ ); +} diff --git a/apps/apollo-vertex/app/(preview)/preview/shell-minimal/page.tsx b/apps/apollo-vertex/app/(preview)/preview/shell-minimal/page.tsx new file mode 100644 index 000000000..cf87403a9 --- /dev/null +++ b/apps/apollo-vertex/app/(preview)/preview/shell-minimal/page.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { Eye, EyeOff } from "lucide-react"; +import { useState } from "react"; +import { ShellTemplate } from "@/templates/ShellTemplate"; +import { LoanQcDashboard } from "./loan-qc-dashboard"; + +function VisibilityToggle({ + visible, + onToggle, +}: { + visible: boolean; + onToggle: () => void; +}) { + const Icon = visible ? Eye : EyeOff; + + return ( + + ); +} + +export default function ShellMinimalPreviewPage() { + const [contentVisible, setContentVisible] = useState(true); + + return ( + setContentVisible((v) => !v)} + /> + } + > + + + ); +} diff --git a/apps/apollo-vertex/app/(preview)/preview/shell/invoice-dashboard.tsx b/apps/apollo-vertex/app/(preview)/preview/shell/invoice-dashboard.tsx new file mode 100644 index 000000000..bf3520c25 --- /dev/null +++ b/apps/apollo-vertex/app/(preview)/preview/shell/invoice-dashboard.tsx @@ -0,0 +1,205 @@ +"use client"; + +import { + CheckCircle, + Clock, + FileText, + AlertTriangle, + TrendingUp, +} from "lucide-react"; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +const kpis = [ + { label: "Total Invoices", value: "1,247", icon: FileText, change: "+12%" }, + { label: "Pending Review", value: "83", icon: Clock, change: "-5%" }, + { label: "Processed Today", value: "156", icon: CheckCircle, change: "+23%" }, + { label: "Success Rate", value: "98.2%", icon: TrendingUp, change: "+0.4%" }, +]; + +const invoices = [ + { id: "INV-4021", vendor: "Acme Corp", amount: "$12,450.00", status: "Processed" as const, date: "Feb 25, 2026" }, + { id: "INV-4020", vendor: "Global Supplies Ltd", amount: "$3,280.50", status: "Pending" as const, date: "Feb 25, 2026" }, + { id: "INV-4019", vendor: "TechParts Inc", amount: "$8,920.00", status: "In Review" as const, date: "Feb 24, 2026" }, + { id: "INV-4018", vendor: "Office Depot", amount: "$1,150.75", status: "Processed" as const, date: "Feb 24, 2026" }, + { id: "INV-4017", vendor: "CloudServ Solutions", amount: "$24,000.00", status: "Failed" as const, date: "Feb 23, 2026" }, + { id: "INV-4016", vendor: "Metro Logistics", amount: "$6,780.00", status: "Processed" as const, date: "Feb 23, 2026" }, +]; + +const statusVariant: Record = { + Processed: "default", + Pending: "secondary", + Failed: "destructive", + "In Review": "outline", +}; + +const activityBars = [ + { label: "Mon", height: 60 }, + { label: "Tue", height: 85 }, + { label: "Wed", height: 45 }, + { label: "Thu", height: 92 }, + { label: "Fri", height: 78 }, + { label: "Sat", height: 30 }, + { label: "Sun", height: 15 }, +]; + +const recentActivity = [ + { text: "INV-4021 processed successfully", time: "2 min ago" }, + { text: "INV-4020 submitted for review", time: "15 min ago" }, + { text: "Batch processing completed (42 invoices)", time: "1 hr ago" }, + { text: "INV-4017 failed — missing PO number", time: "3 hrs ago" }, +]; + +export function InvoiceDashboard({ visible }: { visible: boolean }) { + if (!visible) return null; + + return ( +
+ {/* Header */} +
+

Invoice Processing

+

+ Monitor and manage invoice automation workflows +

+
+ + {/* KPI Cards */} +
+ {kpis.map((kpi) => ( + + +
+ + {kpi.label} + + +
+
+ +
{kpi.value}
+

+ {kpi.change} from last week +

+
+
+ ))} +
+ + {/* Invoices Table */} + + + Recent Invoices + + + + + + Invoice + Vendor + Amount + Status + Date + + + + {invoices.map((inv) => ( + + {inv.id} + {inv.vendor} + {inv.amount} + + {inv.status} + + {inv.date} + + ))} + +
+
+
+ + {/* Bottom Row */} +
+ {/* Processing Activity */} + + + Processing Activity + + +
+ {activityBars.map((bar) => ( +
+
+ {bar.label} +
+ ))} +
+ + + + {/* Recent Activity */} + + + Recent Activity + + +
+ {recentActivity.map((event, i) => ( +
+
+
+

{event.text}

+

{event.time}

+
+
+ ))} +
+ + +
+ + {/* Processing Pipeline */} + + + Processing Pipeline + + +
+
+ OCR Extraction + 96% +
+ +
+ Field Validation + 88% +
+ +
+ Approval Routing + 72% +
+ +
+
+
+
+ ); +} diff --git a/apps/apollo-vertex/app/(preview)/preview/shell/page.tsx b/apps/apollo-vertex/app/(preview)/preview/shell/page.tsx new file mode 100644 index 000000000..f3c67c4ac --- /dev/null +++ b/apps/apollo-vertex/app/(preview)/preview/shell/page.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { AnimatePresence, motion } from "framer-motion"; +import { Eye, EyeOff } from "lucide-react"; +import { useState } from "react"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { useLocalStorage } from "@/registry/use-local-storage/use-local-storage"; +import { ShellTemplate } from "@/templates/ShellTemplate"; +import { InvoiceDashboard } from "./invoice-dashboard"; + +function VisibilityToggle({ + visible, + onToggle, +}: { + visible: boolean; + onToggle: () => void; +}) { + const [isCollapsed] = useLocalStorage("sidebar-collapsed", false); + const Icon = visible ? Eye : EyeOff; + + const content = ( + + ); + + if (isCollapsed) { + return ( + + + {content} + + Toggle Content + + + + ); + } + + return content; +} + +export default function ShellPreviewPage() { + const [contentVisible, setContentVisible] = useState(true); + + return ( + setContentVisible((v) => !v)} + /> + } + > + + + ); +} diff --git a/apps/apollo-vertex/app/globals.css b/apps/apollo-vertex/app/globals.css index fa5f28f21..6d228f12c 100644 --- a/apps/apollo-vertex/app/globals.css +++ b/apps/apollo-vertex/app/globals.css @@ -9,14 +9,20 @@ @custom-variant dark (&:is(.dark *)); /* or nextra-theme-blog/style.css */ +@theme inline { + --color-brand-orange: var(--brand-orange); +} + :root { /* Override Nextra's background to match our theme */ --x-color-nextra-bg: var(--background); + --brand-orange: #fa4616; } .dark { /* Override Nextra's background to match our theme */ --x-color-nextra-bg: var(--background); + --brand-orange: #fa4616; } @layer base { diff --git a/apps/apollo-vertex/app/shadcn-components/avatar/page.mdx b/apps/apollo-vertex/app/shadcn-components/avatar/page.mdx index 385a6d30e..1df912b02 100644 --- a/apps/apollo-vertex/app/shadcn-components/avatar/page.mdx +++ b/apps/apollo-vertex/app/shadcn-components/avatar/page.mdx @@ -50,5 +50,5 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" CN - + ``` diff --git a/apps/apollo-vertex/app/vertex-components/shell/page.mdx b/apps/apollo-vertex/app/vertex-components/shell/page.mdx index 704ab68a8..e3738bc40 100644 --- a/apps/apollo-vertex/app/vertex-components/shell/page.mdx +++ b/apps/apollo-vertex/app/vertex-components/shell/page.mdx @@ -10,6 +10,8 @@ A component that includes OAuth2 authentication and a collapsible sidebar.
+Open standalone preview ↗ + ## Minimal Header Variant Use the `variant="minimal"` prop to render a horizontal header layout instead of the default sidebar. @@ -20,6 +22,8 @@ Use the `variant="minimal"` prop to render a horizontal header layout instead of
+Open standalone preview ↗ + ## Features - **OAuth2 Authentication**: Built-in authorization code flow with PKCE diff --git a/apps/apollo-vertex/locales/en.json b/apps/apollo-vertex/locales/en.json index d12c3aac5..b0944d477 100644 --- a/apps/apollo-vertex/locales/en.json +++ b/apps/apollo-vertex/locales/en.json @@ -25,6 +25,7 @@ "changes_apply_instantly": "Changes apply instantly", "click_me": "Click me", "close": "Close", + "close_sidebar": "Close sidebar", "copy_payment_id": "Copy payment ID", "custom": "Custom", "dark": "Dark", @@ -41,6 +42,7 @@ "hide": "Hide", "import": "Import", "info": "Info", + "language": "Language", "light": "Light", "light_mode": "Light Mode", "load_from_preset": "Load from preset:", @@ -54,6 +56,7 @@ "no_results": "No results.", "of": "of", "open_menu": "Open menu", + "open_sidebar": "Open sidebar", "outline": "Outline", "page": "Page", "preview": "Preview", diff --git a/apps/apollo-vertex/next-env.d.ts b/apps/apollo-vertex/next-env.d.ts index 9edff1c7c..c4b7818fb 100644 --- a/apps/apollo-vertex/next-env.d.ts +++ b/apps/apollo-vertex/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/apollo-vertex/public/UiPath.svg b/apps/apollo-vertex/public/UiPath.svg new file mode 100644 index 000000000..92eb9870f --- /dev/null +++ b/apps/apollo-vertex/public/UiPath.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/apollo-vertex/registry/card/card.tsx b/apps/apollo-vertex/registry/card/card.tsx index 4f880247e..bd9db2e5e 100644 --- a/apps/apollo-vertex/registry/card/card.tsx +++ b/apps/apollo-vertex/registry/card/card.tsx @@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
void; +}) { + const { t } = useTranslation(); + const [hovered, setHovered] = useState(false); + + return ( + + + + + + + {t("open_sidebar")} + + + + ); +} + export const Company = ({ companyName, productName, companyLogo, }: CompanyProps) => { + const { t } = useTranslation(); const [isCollapsed, setIsCollapsed] = useLocalStorage( "sidebar-collapsed", false, ); const iconElement = ( {companyLogo ? ( {companyLogo.alt} ) : ( - + )} ); return ( -
+
{isCollapsed ? ( - - - - - - -
- {companyName} - {productName} -
-
-
-
+ setIsCollapsed(false)} + /> ) : ( iconElement )} @@ -92,7 +153,7 @@ export const Company = ({ exit="exit" transition={fastFadeTransition} > - + {companyName} @@ -116,14 +177,22 @@ export const Company = ({ exit="exit" transition={fastFadeTransition} > - + + + + + + + {t("close_sidebar")} + + + )} diff --git a/apps/apollo-vertex/registry/shell/shell-layout.tsx b/apps/apollo-vertex/registry/shell/shell-layout.tsx index 95ea57503..bf04aad18 100644 --- a/apps/apollo-vertex/registry/shell/shell-layout.tsx +++ b/apps/apollo-vertex/registry/shell/shell-layout.tsx @@ -1,4 +1,4 @@ -import type { PropsWithChildren } from "react"; +import type { PropsWithChildren, ReactNode } from "react"; import type { CompanyLogo } from "./shell"; import { Sidebar } from "./shell-sidebar"; import { useTheme } from "./shell-theme-provider"; @@ -10,146 +10,75 @@ interface ShellLayoutProps { productName: string; variant?: "minimal"; companyLogo?: CompanyLogo; + sidebarActions?: ReactNode; + headerActions?: ReactNode; } function DarkGradientBackground() { return ( -
- {/* ellipse 1 - top left */} -
- - - - - - - - - - - + /> - {/* Ellipse 2 - center */} + {/* Organic shape — upper left indigo (wide, stretched) */}
- {/* ellipse 3 - bottom right */} - + /> - {/* Ellipse 4 - top right */} + {/* Organic shape — lower right cyan (stretched horizontal) */}
- {/* Noise overlay to reduce banding */} + {/* Grain texture */}
- {/* ellipse 1 - top left */} -
+ + {/* Organic shape — upper left soft periwinkle (wide, stretched) */} +
- - - - - - - - - - - + /> - {/* ellipse 2 - center */} + {/* Organic shape — center lavender (oblong, diagonal) */}
- {/* ellipse 3 - top right */} + {/* Organic shape — lower right aqua (stretched horizontal) */}
- - {/* Noise overlay to reduce banding */} -
); } @@ -277,17 +163,22 @@ export function ShellLayout({ productName, variant, companyLogo, + sidebarActions, + headerActions, }: PropsWithChildren) { if (variant === "minimal") { return ( -
- -
+
+
+ +
{children}
@@ -297,12 +188,13 @@ export function ShellLayout({ } return ( -
+
diff --git a/apps/apollo-vertex/registry/shell/shell-minimal-company.tsx b/apps/apollo-vertex/registry/shell/shell-minimal-company.tsx index 9edd4c837..3896ef0f7 100644 --- a/apps/apollo-vertex/registry/shell/shell-minimal-company.tsx +++ b/apps/apollo-vertex/registry/shell/shell-minimal-company.tsx @@ -1,3 +1,4 @@ +import { Box } from "lucide-react"; import type { CompanyLogo } from "./shell"; interface MinimalCompanyProps { @@ -13,19 +14,19 @@ export const MinimalCompany = ({ }: MinimalCompanyProps) => { return (
-
+
{companyLogo ? ( {companyLogo.alt} ) : ( -
+ )}
- + {companyName} {productName} diff --git a/apps/apollo-vertex/registry/shell/shell-nav-item.tsx b/apps/apollo-vertex/registry/shell/shell-nav-item.tsx index d5c7af1a4..11c6212e0 100644 --- a/apps/apollo-vertex/registry/shell/shell-nav-item.tsx +++ b/apps/apollo-vertex/registry/shell/shell-nav-item.tsx @@ -38,7 +38,7 @@ export const NavItem = ({ to, icon: Icon, text }: NavItemProps) => { isCollapsed ? "w-8 justify-center" : "pr-3", isActive ? "bg-sidebar-accent text-sidebar-accent-foreground" - : "text-sidebar-foreground/70 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground", + : "text-sidebar-foreground/80 hover:bg-sidebar-accent/50 hover:text-sidebar-foreground", )} > { const [isCollapsed] = useLocalStorage("sidebar-collapsed", false); - const sidebarWidth = isCollapsed ? "w-[48px]" : "w-[264px]"; + const sidebarWidth = isCollapsed ? "w-16" : "w-[280px]"; if (variant === "minimal") { return ( -
+
-
@@ -60,10 +62,10 @@ export const Sidebar = ({ -