Function bodies 234 total
OnboardingTitle function · typescript · L36-L42 (7 LOC)app/components/onboarding/OnboardingCard.tsx
export function OnboardingTitle({ children }: OnboardingTitleProps) {
return (
<h1 className="text-2xl font-bold text-gray-900 mb-2 text-center">
{children}
</h1>
);
}OnboardingSubtitle function · typescript · L48-L54 (7 LOC)app/components/onboarding/OnboardingCard.tsx
export function OnboardingSubtitle({ children }: OnboardingSubtitleProps) {
return (
<p className="text-gray-600 text-center mb-6">
{children}
</p>
);
}OnboardingFooter function · typescript · L61-L67 (7 LOC)app/components/onboarding/OnboardingCard.tsx
export function OnboardingFooter({ children, className = '' }: OnboardingFooterProps) {
return (
<div className={`mt-8 pt-6 border-t border-gray-100 ${className}`}>
{children}
</div>
);
}OnboardingHelperText function · typescript · L73-L79 (7 LOC)app/components/onboarding/OnboardingCard.tsx
export function OnboardingHelperText({ children }: OnboardingHelperTextProps) {
return (
<p className="text-sm text-gray-500 mt-3 text-center">
{children}
</p>
);
}TimeIndicator function · typescript · L86-L97 (12 LOC)app/components/onboarding/OnboardingCard.tsx
export function TimeIndicator({ text }: TimeIndicatorProps) {
return (
<div className="flex justify-center mb-4">
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-xs font-medium">
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{text}
</span>
</div>
);
}ProgressIndicator function · typescript · L10-L60 (51 LOC)app/components/onboarding/ProgressIndicator.tsx
export function ProgressIndicator({ currentStep, totalSteps }: ProgressIndicatorProps) {
return (
<div className="flex items-center gap-2 px-4 py-2 bg-white/80 backdrop-blur-sm rounded-full border border-gray-200 shadow-sm">
{Array.from({ length: totalSteps }, (_, i) => {
const step = i + 1;
const isCompleted = step < currentStep;
const isCurrent = step === currentStep;
return (
<div key={step} className="flex items-center">
<motion.div
initial={false}
animate={{
scale: isCurrent ? 1 : 0.85,
}}
className="relative flex items-center justify-center"
>
<div
className={`
w-2.5 h-2.5 rounded-full transition-all duration-300
${isCompleted ? 'bg-emerald-500' : isCurrent ? 'bg-gray-900' : 'bg-gray-300'}
${isCurrent ? 'ring-4 ring-gray-900/10' : ''}
CheckIcon function · typescript · L37-L47 (11 LOC)app/components/pricing/FeatureComparison.tsx
function CheckIcon() {
return (
<svg className="w-5 h-5 text-success-500" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
);
}Repobility · MCP-ready · https://repobility.com
XIcon function · typescript · L49-L59 (11 LOC)app/components/pricing/FeatureComparison.tsx
function XIcon() {
return (
<svg className="w-5 h-5 text-neutral-600" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
);
}FeatureValue function · typescript · L61-L66 (6 LOC)app/components/pricing/FeatureComparison.tsx
function FeatureValue({ value }: { value: boolean | string }) {
if (typeof value === 'boolean') {
return value ? <CheckIcon /> : <XIcon />;
}
return <span className="text-sm text-neutral-300">{value}</span>;
}FeatureComparison function · typescript · L68-L176 (109 LOC)app/components/pricing/FeatureComparison.tsx
export function FeatureComparison() {
const [isSticky, setIsSticky] = useState(false);
const headerRef = useRef<HTMLDivElement>(null);
const tableRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleScroll = () => {
if (headerRef.current && tableRef.current) {
const tableRect = tableRef.current.getBoundingClientRect();
const headerRect = headerRef.current.getBoundingClientRect();
// Make header sticky when table is in view but header would scroll out
setIsSticky(tableRect.top < 80 && tableRect.bottom > headerRect.height + 80);
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// Group features by category
const groupedFeatures = features.reduce((acc, feature) => {
const category = feature.category || 'Other';
if (!acc[category]) {
acc[category] = [];
}
acc[category].push(feature);
return acc;
PricingCard function · typescript · L24-L166 (143 LOC)app/components/pricing/PricingCard.tsx
export function PricingCard({
name,
description,
monthlyPrice,
annualPrice,
isAnnual,
features,
popular = false,
ctaText,
ctaHref,
badge,
}: PricingCardProps) {
const currentPrice = isAnnual ? annualPrice : monthlyPrice;
const monthlyEquivalent = isAnnual ? Math.round(annualPrice / 12) : monthlyPrice;
const savings = isAnnual && monthlyPrice > 0
? Math.round(((monthlyPrice * 12 - annualPrice) / (monthlyPrice * 12)) * 100)
: 0;
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className={`
relative flex flex-col p-8 rounded-2xl transition-all duration-300
${popular
? 'bg-gradient-to-b from-neutral-800 to-neutral-900 border-2 border-primary-500/50 shadow-xl shadow-primary-500/10 scale-105 z-10'
: 'bg-neutral-900/50 border border-neutral-800 hover:border-neutral-700'
}
`}
PricingFAQ function · typescript · L92-L131 (40 LOC)app/components/pricing/PricingFAQ.tsx
export function PricingFAQ() {
const [openIndex, setOpenIndex] = useState<number | null>(0);
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="max-w-3xl mx-auto"
>
<div className="bg-neutral-900/50 border border-neutral-800 rounded-2xl p-6 md:p-8">
{faqItems.map((item, index) => (
<FAQAccordion
key={index}
item={item}
isOpen={openIndex === index}
onToggle={() => setOpenIndex(openIndex === index ? null : index)}
/>
))}
</div>
{/* Contact CTA */}
<div className="mt-8 text-center">
<p className="text-neutral-400 mb-4">
Still have questions?
</p>
<a
href="mailto:[email protected]"
className="inline-flex items-center gap-2 text-primary-400 hover:text-primary-300 font-medium transPricingToggle function · typescript · L10-L61 (52 LOC)app/components/pricing/PricingToggle.tsx
export function PricingToggle({ isAnnual, onToggle }: PricingToggleProps) {
return (
<div className="flex items-center justify-center gap-4">
<span
className={`text-sm font-medium transition-colors ${
!isAnnual ? 'text-white' : 'text-neutral-500'
}`}
>
Monthly
</span>
{/* Toggle Switch */}
<button
onClick={() => onToggle(!isAnnual)}
className={`
relative w-14 h-7 rounded-full transition-colors duration-300
${isAnnual ? 'bg-primary-500' : 'bg-neutral-700'}
`}
aria-label={isAnnual ? 'Switch to monthly billing' : 'Switch to annual billing'}
>
<motion.div
className="absolute top-0.5 w-6 h-6 bg-white rounded-full shadow-md"
animate={{ left: isAnnual ? '1.75rem' : '0.125rem' }}
transition={{ type: 'spring', stiffness: 500, damping: 30 }}
/>
</button>
<span
className={`text-sm font-medium transition-loadHistory function · typescript · L31-L43 (13 LOC)app/components/ResearchChat.tsx
async function loadHistory() {
try {
const response = await fetch(`/api/research/chat/${applicationId}`);
if (response.ok) {
const data = await response.json();
setMessages(data.messages || []);
}
} catch (err) {
console.error('Failed to load chat history:', err);
} finally {
setIsLoadingHistory(false);
}
}SearchFilterBar function · typescript · L14-L154 (141 LOC)app/components/SearchFilterBar.tsx
export function SearchFilterBar({
searchQuery,
onSearchChange,
statusFilter,
onStatusFilterChange,
onAddClick,
}: SearchFilterBarProps) {
const inputRef = useRef<HTMLInputElement>(null);
// Keyboard shortcut: Cmd/Ctrl + K to focus search
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
inputRef.current?.focus();
}
// Escape to clear and blur
if (e.key === 'Escape' && document.activeElement === inputRef.current) {
onSearchChange('');
inputRef.current?.blur();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [onSearchChange]);
return (
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-3 mb-6">
{/* Search Input - Command palette style */}
<div className="relative flex-1 max-w-lg group">Repobility — same analyzer, your code, free for public repos · /scan/
SuggestedQuestions function · typescript · L9-L38 (30 LOC)app/components/SuggestedQuestions.tsx
export function SuggestedQuestions({ questions, onSelect, disabled = false }: SuggestedQuestionsProps) {
if (questions.length === 0) return null;
return (
<div className="flex flex-wrap gap-2">
{questions.map((question, index) => (
<button
key={index}
onClick={() => onSelect(question)}
disabled={disabled}
className={`
px-3 py-2
text-sm text-left
rounded-lg
border border-slate-200 dark:border-slate-700
bg-white dark:bg-slate-800
text-slate-700 dark:text-slate-300
transition-all duration-200
${disabled
? 'opacity-50 cursor-not-allowed'
: 'hover:border-blue-300 dark:hover:border-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 hover:shadow-sm cursor-pointer'
}
`}
>
{question}
</button>
))}
</div>
);
}Badge function · typescript · L73-L99 (27 LOC)app/components/ui/Badge.tsx
export function Badge({
variant = 'default',
size = 'md',
dot = false,
icon,
children,
className = '',
}: BadgeProps) {
return (
<span
className={`
inline-flex items-center gap-1.5
font-medium rounded-full
transition-colors duration-150
${variants[variant]}
${sizes[size]}
${className}
`}
>
{dot && (
<span className={`rounded-full ${dotColors[variant]} ${dotSizes[size]}`} />
)}
{icon && <span className={iconSizes[size]}>{icon}</span>}
{children}
</span>
);
}StatusBadge function · typescript · L102-L145 (44 LOC)app/components/ui/Badge.tsx
export function StatusBadge({
status,
closeReason,
size = 'md',
}: {
status: 'applied' | 'interviewing' | 'offer' | 'closed';
closeReason?: 'rejected' | 'withdrawn' | 'ghosted' | 'accepted' | null;
size?: BadgeSize;
}) {
if (status === 'closed' && closeReason) {
const reasonVariants: Record<string, BadgeVariant> = {
rejected: 'danger',
withdrawn: 'default',
ghosted: 'warning',
accepted: 'success',
};
const reasonLabels: Record<string, string> = {
rejected: 'Rejected',
withdrawn: 'Withdrawn',
ghosted: 'Ghosted',
accepted: 'Accepted',
};
return (
<Badge variant={reasonVariants[closeReason]} size={size} dot>
{reasonLabels[closeReason]}
</Badge>
);
}
const statusLabels: Record<string, string> = {
applied: 'Applied',
interviewing: 'Interviewing',
offer: 'Offer',
closed: 'Closed',
};
return (
<Badge variant={status as BadgeVariant} size={size} dot>
{CountBadge function · typescript · L148-L163 (16 LOC)app/components/ui/Badge.tsx
export function CountBadge({ count, className = '' }: { count: number; className?: string }) {
return (
<span
className={`
inline-flex items-center justify-center
min-w-[1.25rem] h-5 px-1.5
text-xs font-medium
bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400
rounded-full
${className}
`}
>
{count}
</span>
);
}CardHeader function · typescript · L89-L103 (15 LOC)app/components/ui/Card.tsx
export function CardHeader({ className = '', children, ...props }: CardHeaderProps) {
return (
<div
className={`
flex items-center justify-between
pb-4 mb-4
border-b border-gray-100 dark:border-gray-800
${className}
`}
{...props}
>
{children}
</div>
);
}CardTitle function · typescript · L110-L122 (13 LOC)app/components/ui/Card.tsx
export function CardTitle({ as: Component = 'h3', className = '', children, ...props }: CardTitleProps) {
return (
<Component
className={`
text-base font-semibold text-gray-900 dark:text-gray-100
${className}
`}
{...props}
>
{children}
</Component>
);
}CardDescription function · typescript · L128-L140 (13 LOC)app/components/ui/Card.tsx
export function CardDescription({ className = '', children, ...props }: CardDescriptionProps) {
return (
<p
className={`
text-sm text-gray-500 dark:text-gray-400
${className}
`}
{...props}
>
{children}
</p>
);
}CardContent function · typescript · L146-L152 (7 LOC)app/components/ui/Card.tsx
export function CardContent({ className = '', children, ...props }: CardContentProps) {
return (
<div className={className} {...props}>
{children}
</div>
);
}Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
CardFooter function · typescript · L158-L172 (15 LOC)app/components/ui/Card.tsx
export function CardFooter({ className = '', children, ...props }: CardFooterProps) {
return (
<div
className={`
flex items-center gap-3
pt-4 mt-4
border-t border-gray-100 dark:border-gray-800
${className}
`}
{...props}
>
{children}
</div>
);
}useDropdown function · typescript · L27-L33 (7 LOC)app/components/ui/Dropdown.tsx
function useDropdown() {
const context = useContext(DropdownContext);
if (!context) {
throw new Error('Dropdown components must be used within a Dropdown');
}
return context;
}Dropdown function · typescript · L41-L99 (59 LOC)app/components/ui/Dropdown.tsx
export function Dropdown({ children, onOpenChange }: DropdownProps) {
const [isOpen, setIsOpenState] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const triggerRef = useRef<HTMLButtonElement>(null);
const menuRef = useRef<HTMLDivElement>(null);
const setIsOpen = useCallback(
(open: boolean) => {
setIsOpenState(open);
onOpenChange?.(open);
if (!open) {
setActiveIndex(-1);
}
},
[onOpenChange]
);
// Close on click outside
useEffect(() => {
const handleClickOutside = (event: globalThis.MouseEvent) => {
if (
menuRef.current &&
!menuRef.current.contains(event.target as Node) &&
triggerRef.current &&
!triggerRef.current.contains(event.target as Node)
) {
setIsOpen(false);
}
};
if (isOpen) {
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
DropdownTrigger function · typescript · L108-L163 (56 LOC)app/components/ui/Dropdown.tsx
export function DropdownTrigger({ children, className = '', asChild = false }: DropdownTriggerProps) {
const { isOpen, setIsOpen, triggerRef, menuRef, setActiveIndex } = useDropdown();
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
setIsOpen(true);
setActiveIndex(0);
}
if (event.key === 'ArrowUp') {
event.preventDefault();
setIsOpen(true);
// Focus last item
const items = menuRef.current?.querySelectorAll('[role="menuitem"]');
if (items) {
setActiveIndex(items.length - 1);
}
}
};
if (asChild) {
return <>{children}</>;
}
return (
<button
ref={triggerRef}
onClick={() => setIsOpen(!isOpen)}
onKeyDown={handleKeyDown}
aria-haspopup="menu"
aria-expanded={isOpen}
className={`
inline-flex items-center justify-center gap-2
DropdownMenu function · typescript · L173-L253 (81 LOC)app/components/ui/Dropdown.tsx
export function DropdownMenu({
children,
align = 'start',
side = 'bottom',
className = '',
}: DropdownMenuProps) {
const { isOpen, menuRef, activeIndex, setActiveIndex, setIsOpen, triggerRef } = useDropdown();
const itemsRef = useRef<HTMLElement[]>([]);
const alignments = {
start: 'left-0',
center: 'left-1/2 -translate-x-1/2',
end: 'right-0',
};
const sides = {
top: 'bottom-full mb-1',
bottom: 'top-full mt-1',
};
// Focus active item
useEffect(() => {
if (isOpen && activeIndex >= 0 && itemsRef.current[activeIndex]) {
itemsRef.current[activeIndex].focus();
}
}, [isOpen, activeIndex]);
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
const items = menuRef.current?.querySelectorAll('[role="menuitem"]:not([disabled])');
if (!items) return;
const itemCount = items.length;
switch (event.key) {
case 'ArrowDown':
event.preventDefault();
setActiveIndex((activeIndex + 1) % iDropdownItem function · typescript · L266-L321 (56 LOC)app/components/ui/Dropdown.tsx
export function DropdownItem({
children,
onClick,
disabled = false,
destructive = false,
icon,
shortcut,
className = '',
}: DropdownItemProps) {
const { setIsOpen } = useDropdown();
const handleClick = () => {
if (!disabled && onClick) {
onClick();
setIsOpen(false);
}
};
const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
handleClick();
}
};
return (
<button
role="menuitem"
onClick={handleClick}
onKeyDown={handleKeyDown}
disabled={disabled}
className={`
w-full flex items-center gap-2
px-3 py-2 text-sm text-left
transition-colors duration-100
focus:outline-none
${
disabled
? 'opacity-50 cursor-not-allowed'
: destructive
? 'text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 focus:bg-red-50 daDropdownLabel function · typescript · L334-L347 (14 LOC)app/components/ui/Dropdown.tsx
export function DropdownLabel({ children, className = '' }: DropdownLabelProps) {
return (
<div
className={`
px-3 py-1.5 text-xs font-medium
text-gray-500 dark:text-gray-400
uppercase tracking-wider
${className}
`}
>
{children}
</div>
);
}DropdownCheckboxItem function · typescript · L358-L411 (54 LOC)app/components/ui/Dropdown.tsx
export function DropdownCheckboxItem({
children,
checked,
onCheckedChange,
disabled = false,
className = '',
}: DropdownCheckboxItemProps) {
const handleClick = () => {
if (!disabled) {
onCheckedChange(!checked);
}
};
return (
<button
role="menuitemcheckbox"
aria-checked={checked}
onClick={handleClick}
disabled={disabled}
className={`
w-full flex items-center gap-2
px-3 py-2 text-sm text-left
transition-colors duration-100
focus:outline-none
${
disabled
? 'opacity-50 cursor-not-allowed'
: 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-gray-800'
}
${className}
`}
>
<span
className={`
w-4 h-4 flex-shrink-0 rounded border
flex items-center justify-center
transition-colors duration-150
${
checked
Want this analysis on your repo? https://repobility.com/scan/
Modal function · typescript · L25-L132 (108 LOC)app/components/ui/Modal.tsx
export function Modal({
isOpen,
onClose,
children,
size = 'md',
closeOnBackdrop = true,
closeOnEscape = true,
showCloseButton = true,
'data-testid': dataTestId,
}: ModalProps) {
const overlayRef = useRef<HTMLDivElement>(null);
const contentRef = useRef<HTMLDivElement>(null);
// Handle escape key
const handleKeyDown = useCallback(
(event: globalThis.KeyboardEvent) => {
if (closeOnEscape && event.key === 'Escape') {
onClose();
}
},
[closeOnEscape, onClose]
);
// Handle backdrop click
const handleBackdropClick = (event: MouseEvent<HTMLDivElement>) => {
if (closeOnBackdrop && event.target === overlayRef.current) {
onClose();
}
};
// Lock body scroll and add event listeners
useEffect(() => {
if (isOpen) {
const originalOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
document.addEventListener('keydown', handleKeyDown);
// Focus trap - focus the mModalHeader function · typescript · L140-L152 (13 LOC)app/components/ui/Modal.tsx
export function ModalHeader({ children, className = '' }: ModalHeaderProps) {
return (
<div
className={`
px-6 py-4
border-b border-gray-100 dark:border-gray-800
${className}
`}
>
{children}
</div>
);
}ModalTitle function · typescript · L159-L170 (12 LOC)app/components/ui/Modal.tsx
export function ModalTitle({ children, className = '' }: ModalTitleProps) {
return (
<h2
className={`
text-lg font-semibold text-gray-900 dark:text-gray-100
${className}
`}
>
{children}
</h2>
);
}ModalDescription function · typescript · L177-L188 (12 LOC)app/components/ui/Modal.tsx
export function ModalDescription({ children, className = '' }: ModalDescriptionProps) {
return (
<p
className={`
mt-1 text-sm text-gray-500 dark:text-gray-400
${className}
`}
>
{children}
</p>
);
}ModalBody function · typescript · L195-L207 (13 LOC)app/components/ui/Modal.tsx
export function ModalBody({ children, className = '' }: ModalBodyProps) {
return (
<div
className={`
px-6 py-4
max-h-[60vh] overflow-y-auto
${className}
`}
>
{children}
</div>
);
}ModalFooter function · typescript · L214-L227 (14 LOC)app/components/ui/Modal.tsx
export function ModalFooter({ children, className = '' }: ModalFooterProps) {
return (
<div
className={`
px-6 py-4
border-t border-gray-100 dark:border-gray-800
flex items-center justify-end gap-3
${className}
`}
>
{children}
</div>
);
}ConfirmModal function · typescript · L242-L339 (98 LOC)app/components/ui/Modal.tsx
export function ConfirmModal({
isOpen,
onClose,
onConfirm,
title,
description,
confirmText = 'Confirm',
cancelText = 'Cancel',
variant = 'default',
isLoading = false,
}: ConfirmModalProps) {
const iconColors = {
danger: 'text-red-500 dark:text-red-400',
warning: 'text-amber-500 dark:text-amber-400',
default: 'text-blue-500 dark:text-blue-400',
};
const buttonVariants = {
danger: 'bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600',
warning: 'bg-amber-600 hover:bg-amber-700 dark:bg-amber-500 dark:hover:bg-amber-600',
default: 'bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600',
};
return (
<Modal isOpen={isOpen} onClose={onClose} size="sm" showCloseButton={false}>
<div className="p-6 text-center">
<div
className={`
mx-auto w-12 h-12 rounded-full
flex items-center justify-center
bg-gray-100 dark:bg-gray-800
${iconColors[variaRootLayout function · typescript · L20-L34 (15 LOC)app/layout.tsx
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
);
}Repobility · MCP-ready · https://repobility.com
MarketingLayout function · typescript · L8-L18 (11 LOC)app/(marketing)/layout.tsx
export default function MarketingLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="min-h-screen bg-neutral-950">
{children}
</div>
);
}Nav function · typescript · L33-L85 (53 LOC)app/(marketing)/page.tsx
function Nav() {
return (
<nav className="fixed top-0 left-0 right-0 z-50 px-6 py-4 bg-white/80 backdrop-blur-lg border-b border-gray-100">
<div className="max-w-7xl mx-auto flex items-center justify-between">
{/* Logo */}
<a href="/" className="flex items-center gap-1.5">
<svg className="w-6 h-6" viewBox="0 0 24 24" fill="none">
<path d="M3 18C3 10 7 4 12 4C17 4 21 10 21 18" stroke="url(#logo-gradient-nav)" strokeWidth="1.5" strokeLinecap="round"/>
<path d="M6 17C6 11 8.5 6.5 12 6.5C15.5 6.5 18 11 18 17" stroke="url(#logo-gradient-nav)" strokeWidth="1.5" strokeLinecap="round"/>
<path d="M9 16C9 12 10.5 9 12 9C13.5 9 15 12 15 16" stroke="url(#logo-gradient-nav)" strokeWidth="1.5" strokeLinecap="round"/>
<defs>
<linearGradient id="logo-gradient-nav" x1="3" y1="4" x2="21" y2="18" gradientUnits="userSpaceOnUse">
<stop stopColor="#059669"/>
<stop offset="1" stHeroSection function · typescript · L90-L215 (126 LOC)app/(marketing)/page.tsx
function HeroSection() {
return (
<section className="relative min-h-screen flex items-center bg-gradient-to-b from-gray-50 via-white to-white pt-20">
{/* Subtle decorative elements */}
<div className="absolute top-40 left-10 w-72 h-72 bg-gray-200/50 rounded-full blur-3xl" />
<div className="absolute bottom-20 right-10 w-96 h-96 bg-gray-100/60 rounded-full blur-3xl" />
<div className="relative z-10 max-w-7xl mx-auto px-6 py-20 lg:py-32">
<div className="text-center max-w-4xl mx-auto">
{/* Badge */}
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4 }}
>
<span className="inline-flex items-center gap-2 px-4 py-2 mb-6 rounded-full bg-gray-100 border border-gray-200">
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
<span className="text-sm font-medium text-gray-700">Track • RLogoBar function · typescript · L221-L243 (23 LOC)app/(marketing)/page.tsx
function LogoBar() {
const logos = ['Google', 'Stripe', 'Notion', 'Linear', 'Figma', 'Vercel', 'Spotify'];
return (
<section className="py-16 bg-gray-50 border-y border-gray-100">
<div className="max-w-7xl mx-auto px-6">
<p className="text-center text-sm text-gray-500 mb-8">
Where our users landed their dream jobs
</p>
<div className="flex flex-wrap justify-center items-center gap-8 md:gap-12 lg:gap-16">
{logos.map((logo, idx) => (
<span
key={idx}
className="text-gray-400 font-semibold text-lg hover:text-gray-600 transition-colors"
>
{logo}
</span>
))}
</div>
</div>
</section>
);
}FeatureSections function · typescript · L248-L342 (95 LOC)app/(marketing)/page.tsx
function FeatureSections() {
return (
<section id="features" className="py-24 lg:py-32">
{/* Feature 1: AI Tailored CVs */}
<FeatureBlock
badge="The Magic"
title="AI-Tailored CVs in 30 Seconds"
description="Stop spending hours rewriting your CV for each job. Our AI reads the job description, understands what they're looking for, and rewrites your experience to match. Same facts, better framing."
features={[
'Analyzes job description for key requirements',
'Highlights your most relevant experience',
'Adjusts language to match company tone',
'Generates downloadable PDF instantly'
]}
screenshotAlt="CV generation interface"
imagePosition="right"
accentColor="violet"
>
<CVGeneratorPreview />
</FeatureBlock>
{/* Feature 2: Visual Pipeline */}
<FeatureBlock
badge="Stay Organized"
title="See Every Application at a Glance"
FeatureBlock function · typescript · L347-L434 (88 LOC)app/(marketing)/page.tsx
function FeatureBlock({
badge,
title,
description,
features,
children,
imagePosition,
accentColor
}: {
badge: string;
title: string;
description: string;
features: string[];
children: React.ReactNode;
screenshotAlt: string;
imagePosition: 'left' | 'right';
accentColor: 'violet' | 'blue' | 'emerald' | 'rose';
}) {
const colorMap = {
violet: { badge: 'bg-gray-100 text-gray-700', check: 'text-gray-900' },
blue: { badge: 'bg-blue-100 text-blue-700', check: 'text-blue-500' },
emerald: { badge: 'bg-emerald-100 text-emerald-700', check: 'text-emerald-500' },
rose: { badge: 'bg-rose-100 text-rose-700', check: 'text-rose-500' },
};
const colors = colorMap[accentColor];
const content = (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={imagePosition === 'right' ? fadeInLeft : fadeInRight}
className="flex flex-col justify-center"
>
<span classNCVGeneratorPreview function · typescript · L439-L474 (36 LOC)app/(marketing)/page.tsx
function CVGeneratorPreview() {
return (
<div className="p-6">
<div className="flex items-center justify-between mb-4">
<h4 className="font-semibold text-gray-900">Generate Tailored CV</h4>
<span className="px-2 py-1 text-xs bg-green-100 text-green-700 rounded-full">Ready</span>
</div>
<div className="grid md:grid-cols-2 gap-4">
{/* Input side */}
<div className="space-y-3">
<div className="bg-gray-50 rounded-lg p-3">
<p className="text-xs font-medium text-gray-500 mb-2">Job Description</p>
<p className="text-sm text-gray-700">Senior Product Manager at Stripe - Lead payment infrastructure...</p>
</div>
<button className="w-full py-2 bg-black text-white text-sm font-medium rounded-lg">
Generate Tailored CV
</button>
</div>
{/* Output side */}
<div className="bg-gray-50 rounded-lg p-3">
<div className="flex items-center justKanbanPreview function · typescript · L476-L504 (29 LOC)app/(marketing)/page.tsx
function KanbanPreview() {
return (
<div className="p-6 overflow-x-auto">
<div className="flex gap-3 min-w-[500px]">
{[
{ title: 'Applied', count: 8, color: 'bg-blue-500' },
{ title: 'Interview', count: 3, color: 'bg-amber-500' },
{ title: 'Offer', count: 1, color: 'bg-green-500' },
].map((col, idx) => (
<div key={idx} className="flex-1 bg-gray-50 rounded-lg p-3">
<div className="flex items-center gap-2 mb-3">
<div className={`w-2 h-2 rounded-full ${col.color}`} />
<span className="text-sm font-medium text-gray-700">{col.title}</span>
<span className="text-xs text-gray-400">{col.count}</span>
</div>
<div className="space-y-2">
{[1, 2].map((i) => (
<div key={i} className="bg-white rounded-md p-2 shadow-sm border border-gray-100">
<div className="h-2 bg-gray-200 rounded w-3/4 mb-1" />
Repobility — same analyzer, your code, free for public repos · /scan/
ResearchPreview function · typescript · L506-L554 (49 LOC)app/(marketing)/page.tsx
function ResearchPreview() {
return (
<div className="p-6">
{/* Chat header */}
<div className="flex items-center gap-3 mb-4 pb-3 border-b border-gray-100">
<div className="w-10 h-10 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-lg flex items-center justify-center text-white">
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div>
<h4 className="font-semibold text-gray-900">Research Chat</h4>
<p className="text-sm text-gray-500">Ask anything about Stripe</p>
</div>
</div>
{/* Chat messages */}
<div className="space-y-3 mb-4">
{/* User message */}
<div className="flex justGmailSyncPreview function · typescript · L556-L591 (36 LOC)app/(marketing)/page.tsx
function GmailSyncPreview() {
return (
<div className="p-6">
<div className="flex items-center justify-between mb-4">
<h4 className="font-semibold text-gray-900">Email Activity</h4>
<span className="flex items-center gap-1 text-xs text-green-600">
<span className="w-2 h-2 rounded-full bg-green-500" />
Synced
</span>
</div>
<div className="space-y-3">
{[
{ from: 'Stripe Recruiting', subject: 'Interview Scheduled', status: 'Interview', time: '2h ago' },
{ from: 'Notion Careers', subject: 'Application Received', status: 'Applied', time: '1d ago' },
{ from: 'Linear Team', subject: 'Next Steps', status: 'Interview', time: '3d ago' },
].map((email, idx) => (
<div key={idx} className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
<div className="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center text-xs font-medium text-gray-600">
ExtensionPreview function · typescript · L593-L645 (53 LOC)app/(marketing)/page.tsx
function ExtensionPreview() {
return (
<div className="p-6">
{/* Browser bar mockup */}
<div className="flex items-center gap-2 mb-4 pb-3 border-b border-gray-100">
<div className="flex gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-red-400" />
<div className="w-2.5 h-2.5 rounded-full bg-yellow-400" />
<div className="w-2.5 h-2.5 rounded-full bg-green-400" />
</div>
<div className="flex-1 bg-gray-100 rounded px-3 py-1 text-xs text-gray-500">
linkedin.com/jobs/senior-engineer-stripe
</div>
<div className="w-6 h-6 bg-gray-900 rounded flex items-center justify-center">
<svg className="w-4 h-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
</svg>
</div>
</div>
{/* Extension popup */}
<div className="bg-white border border-g