feat: landing page mvp
This commit is contained in:
288
components/comparison.tsx
Normal file
288
components/comparison.tsx
Normal file
@@ -0,0 +1,288 @@
|
||||
'use client'
|
||||
|
||||
import { ArrowRight, Check, X, Minus } from 'lucide-react'
|
||||
|
||||
type CellValue = 'yes' | 'no' | 'partial' | string
|
||||
|
||||
interface Row {
|
||||
feature: string
|
||||
greywall: CellValue
|
||||
safehouse: CellValue
|
||||
claudeSandbox: CellValue
|
||||
containers: CellValue
|
||||
}
|
||||
|
||||
const rows: Row[] = [
|
||||
{
|
||||
feature: 'Linux support',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'macOS support',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'partial',
|
||||
},
|
||||
{
|
||||
feature: 'Filesystem isolation',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'Network isolation',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'Transparent network capture',
|
||||
greywall: 'Linux',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'Command blocking',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'Real-time violation monitoring',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'Learning mode',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'Works with any agent',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'Sandboxes entire process',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'partial',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'Native tool access',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'No image rebuilds on changes',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'Open source',
|
||||
greywall: 'yes',
|
||||
safehouse: 'yes',
|
||||
claudeSandbox: 'partial',
|
||||
containers: 'yes',
|
||||
},
|
||||
{
|
||||
feature: 'Syscall filtering',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'no',
|
||||
containers: 'partial',
|
||||
},
|
||||
{
|
||||
feature: 'Dynamic allow/deny',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'partial',
|
||||
containers: 'no',
|
||||
},
|
||||
{
|
||||
feature: 'No deprecated APIs',
|
||||
greywall: 'yes',
|
||||
safehouse: 'no',
|
||||
claudeSandbox: 'yes',
|
||||
containers: 'yes',
|
||||
},
|
||||
]
|
||||
|
||||
function CellIcon({ value }: { value: CellValue }) {
|
||||
if (value === 'yes') {
|
||||
return (
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-400/10">
|
||||
<Check className="h-3 w-3 text-green-400" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
if (value === 'no') {
|
||||
return (
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-red-400/10">
|
||||
<X className="h-3 w-3 text-red-400/70" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
if (value === 'partial') {
|
||||
return (
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-yellow-400/10">
|
||||
<Minus className="h-3 w-3 text-yellow-400/70" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<span className="text-xs font-mono text-muted-foreground">{value}</span>
|
||||
)
|
||||
}
|
||||
|
||||
export function Comparison() {
|
||||
return (
|
||||
<section id="comparison" className="py-24 px-6 border-t border-border/30">
|
||||
<div className="mx-auto max-w-5xl">
|
||||
<div className="max-w-2xl mb-12">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<ArrowRight className="h-4 w-4 text-primary" />
|
||||
<span className="text-xs font-sans uppercase tracking-wider text-primary font-medium">
|
||||
How it compares
|
||||
</span>
|
||||
</div>
|
||||
<h2 className="font-serif text-3xl sm:text-4xl font-semibold tracking-tight mb-4">
|
||||
Not all sandboxes are equal.
|
||||
</h2>
|
||||
<p className="text-muted-foreground font-serif text-lg leading-relaxed">
|
||||
Greywall combines filesystem isolation, network control, syscall filtering,
|
||||
and real-time monitoring in a single tool. Here's how it stacks up.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Desktop table */}
|
||||
<div className="hidden md:block rounded-lg border border-border/40 overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-border/40 bg-card/40">
|
||||
<th className="text-left py-3.5 px-4 font-sans font-medium text-muted-foreground text-xs uppercase tracking-wider">
|
||||
Feature
|
||||
</th>
|
||||
<th className="text-center py-3.5 px-3 font-sans font-semibold text-xs uppercase tracking-wider text-primary">
|
||||
Greywall
|
||||
</th>
|
||||
<th className="text-center py-3.5 px-3 font-sans font-medium text-muted-foreground text-xs uppercase tracking-wider">
|
||||
Safehouse
|
||||
</th>
|
||||
<th className="text-center py-3.5 px-3 font-sans font-medium text-muted-foreground text-xs uppercase tracking-wider">
|
||||
Claude Sandbox
|
||||
</th>
|
||||
<th className="text-center py-3.5 px-3 font-sans font-medium text-muted-foreground text-xs uppercase tracking-wider">
|
||||
Containers
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, i) => (
|
||||
<tr
|
||||
key={row.feature}
|
||||
className={`border-b border-border/20 ${i % 2 === 0 ? 'bg-card/10' : ''}`}
|
||||
>
|
||||
<td className="py-3 px-4 font-serif text-sm text-foreground">
|
||||
{row.feature}
|
||||
</td>
|
||||
<td className="py-3 px-3 text-center">
|
||||
<div className="flex justify-center">
|
||||
<CellIcon value={row.greywall} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3 px-3 text-center">
|
||||
<div className="flex justify-center">
|
||||
<CellIcon value={row.safehouse} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3 px-3 text-center">
|
||||
<div className="flex justify-center">
|
||||
<CellIcon value={row.claudeSandbox} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3 px-3 text-center">
|
||||
<div className="flex justify-center">
|
||||
<CellIcon value={row.containers} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Mobile cards */}
|
||||
<div className="md:hidden space-y-2">
|
||||
{rows.map((row) => (
|
||||
<div
|
||||
key={row.feature}
|
||||
className="p-4 rounded-lg border border-border/30 bg-card/20"
|
||||
>
|
||||
<div className="font-serif text-sm text-foreground mb-3">{row.feature}</div>
|
||||
<div className="grid grid-cols-4 gap-1.5 text-center">
|
||||
<div>
|
||||
<div className="text-[10px] font-sans text-primary font-medium mb-1">Greywall</div>
|
||||
<div className="flex justify-center"><CellIcon value={row.greywall} /></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[10px] font-sans text-muted-foreground font-medium mb-1">Safehouse</div>
|
||||
<div className="flex justify-center"><CellIcon value={row.safehouse} /></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[10px] font-sans text-muted-foreground font-medium mb-1">Claude</div>
|
||||
<div className="flex justify-center"><CellIcon value={row.claudeSandbox} /></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[10px] font-sans text-muted-foreground font-medium mb-1">Containers</div>
|
||||
<div className="flex justify-center"><CellIcon value={row.containers} /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="mt-6 flex flex-wrap items-center gap-5 text-xs font-sans text-muted-foreground">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-green-400/10">
|
||||
<Check className="h-3 w-3 text-green-400" />
|
||||
</span>
|
||||
Supported
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-yellow-400/10">
|
||||
<Minus className="h-3 w-3 text-yellow-400/70" />
|
||||
</span>
|
||||
Partial
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-red-400/10">
|
||||
<X className="h-3 w-3 text-red-400/70" />
|
||||
</span>
|
||||
Not supported
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user