Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
This commit is contained in:
@@ -9,7 +9,7 @@ export default function AboutPage() {
|
||||
<header className="border-b border-studio-medium bg-studio-dark">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
|
||||
<Link href="/" className="text-2xl font-bold text-white">
|
||||
Phoenix <span className="text-phoenix-fire">Sankofa</span> Cloud
|
||||
<span className="text-sankofa-gold">Sankofa's</span> Phoenix <span className="text-phoenix-fire">Nexus</span> Cloud
|
||||
</Link>
|
||||
<nav className="flex gap-4">
|
||||
<Link href="/" className="text-gray-400 hover:text-white">
|
||||
|
||||
74
src/app/api/auth/token/route.ts
Normal file
74
src/app/api/auth/token/route.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { cookies } from 'next/headers'
|
||||
|
||||
/**
|
||||
* API route for managing authentication tokens via httpOnly cookies
|
||||
*/
|
||||
|
||||
const COOKIE_NAME = 'auth_token'
|
||||
const MAX_AGE = 60 * 60 * 24 * 7 // 7 days
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { token } = await request.json()
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Token is required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const cookieStore = await cookies()
|
||||
cookieStore.set(COOKIE_NAME, token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: MAX_AGE,
|
||||
path: '/',
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to set token' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const cookieStore = await cookies()
|
||||
const token = cookieStore.get(COOKIE_NAME)?.value
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json(
|
||||
{ error: 'No token found' },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({ token })
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to get token' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE() {
|
||||
try {
|
||||
const cookieStore = await cookies()
|
||||
cookieStore.delete(COOKIE_NAME)
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to delete token' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
86
src/app/api/infrastructure/backup/route.ts
Normal file
86
src/app/api/infrastructure/backup/route.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as zlib from 'zlib'
|
||||
import { promisify } from 'util'
|
||||
|
||||
const gzip = promisify(zlib.gzip)
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'docs/infrastructure/data')
|
||||
const BACKUP_DIR = path.join(process.cwd(), 'docs/infrastructure/backups')
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Ensure backup directory exists
|
||||
if (!fs.existsSync(BACKUP_DIR)) {
|
||||
fs.mkdirSync(BACKUP_DIR, { recursive: true })
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
|
||||
const backupFilename = `backup-${timestamp}.json.gz`
|
||||
const backupPath = path.join(BACKUP_DIR, backupFilename)
|
||||
|
||||
// Read all data files
|
||||
const files = fs.readdirSync(DATA_DIR).filter((f) => f.endsWith('.json'))
|
||||
const backup: Record<string, any> = {}
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(DATA_DIR, file)
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
backup[file] = JSON.parse(content)
|
||||
}
|
||||
|
||||
// Compress and save
|
||||
const jsonData = JSON.stringify(backup, null, 2)
|
||||
const compressed = await gzip(jsonData)
|
||||
fs.writeFileSync(backupPath, compressed)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
filename: backupFilename,
|
||||
timestamp: new Date().toISOString(),
|
||||
files: files.length,
|
||||
})
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to create backup',
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
if (!fs.existsSync(BACKUP_DIR)) {
|
||||
return NextResponse.json({ backups: [] })
|
||||
}
|
||||
|
||||
const files = fs
|
||||
.readdirSync(BACKUP_DIR)
|
||||
.filter((f) => f.endsWith('.json.gz'))
|
||||
.map((f) => {
|
||||
const filePath = path.join(BACKUP_DIR, f)
|
||||
const stats = fs.statSync(filePath)
|
||||
return {
|
||||
filename: f,
|
||||
size: stats.size,
|
||||
created: stats.birthtime.toISOString(),
|
||||
}
|
||||
})
|
||||
.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())
|
||||
|
||||
return NextResponse.json({ backups: files })
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to list backups',
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
114
src/app/api/infrastructure/data/[filename]/route.ts
Normal file
114
src/app/api/infrastructure/data/[filename]/route.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
/**
|
||||
* API route for serving infrastructure data JSON files
|
||||
*
|
||||
* GET /api/infrastructure/data/[filename]
|
||||
*
|
||||
* Serves JSON files from docs/infrastructure/data/ with caching headers
|
||||
*/
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'docs/infrastructure/data')
|
||||
|
||||
// Allowed file extensions
|
||||
const ALLOWED_EXTENSIONS = ['.json']
|
||||
|
||||
// Security: Prevent directory traversal
|
||||
function sanitizeFilename(filename: string): string {
|
||||
// Remove any path separators and only allow alphanumeric, hyphens, underscores, and dots
|
||||
const sanitized = filename.replace(/[^a-zA-Z0-9._-]/g, '')
|
||||
// Ensure it has a valid extension
|
||||
const ext = path.extname(sanitized)
|
||||
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
||||
throw new Error('Invalid file extension')
|
||||
}
|
||||
return sanitized
|
||||
}
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { filename: string } }
|
||||
) {
|
||||
try {
|
||||
// Sanitize filename to prevent directory traversal
|
||||
const filename = sanitizeFilename(params.filename)
|
||||
const filePath = path.join(DATA_DIR, filename)
|
||||
|
||||
// Check if file exists
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return NextResponse.json(
|
||||
{ error: 'File not found' },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
// Read file content
|
||||
const fileContent = fs.readFileSync(filePath, 'utf-8')
|
||||
|
||||
// Parse JSON to validate it's valid JSON
|
||||
let data: unknown
|
||||
try {
|
||||
data = JSON.parse(fileContent)
|
||||
} catch (parseError) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid JSON file' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
// Get file stats for caching
|
||||
const stats = fs.statSync(filePath)
|
||||
|
||||
// Create response
|
||||
const response = NextResponse.json({
|
||||
data,
|
||||
metadata: {
|
||||
filename,
|
||||
lastModified: stats.mtime.toISOString(),
|
||||
size: stats.size,
|
||||
},
|
||||
})
|
||||
|
||||
// Add caching headers
|
||||
const etag = `"${stats.mtime.getTime()}-${stats.size}"`
|
||||
response.headers.set('ETag', etag)
|
||||
response.headers.set('Last-Modified', stats.mtime.toUTCString())
|
||||
response.headers.set('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400')
|
||||
response.headers.set('Content-Type', 'application/json')
|
||||
|
||||
// Check if client has cached version (304 Not Modified)
|
||||
const ifNoneMatch = request.headers.get('if-none-match')
|
||||
if (ifNoneMatch === etag) {
|
||||
return new NextResponse(null, { status: 304 })
|
||||
}
|
||||
|
||||
const ifModifiedSince = request.headers.get('if-modified-since')
|
||||
if (ifModifiedSince) {
|
||||
const ifModifiedSinceDate = new Date(ifModifiedSince)
|
||||
if (stats.mtime <= ifModifiedSinceDate) {
|
||||
return new NextResponse(null, { status: 304 })
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
// Handle security errors
|
||||
if (error instanceof Error && error.message === 'Invalid file extension') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid file type. Only JSON files are allowed.' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Log error for debugging (in production, use proper logging)
|
||||
console.error('Error serving infrastructure data:', error)
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to load file' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
67
src/app/api/infrastructure/import/route.ts
Normal file
67
src/app/api/infrastructure/import/route.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as XLSX from 'xlsx'
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'docs/infrastructure/data')
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const formData = await request.formData()
|
||||
const file = formData.get('file') as File
|
||||
const targetFile = formData.get('targetFile') as string
|
||||
|
||||
if (!file || !targetFile) {
|
||||
return NextResponse.json(
|
||||
{ error: 'File and targetFile are required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(await file.arrayBuffer())
|
||||
const filePath = path.join(DATA_DIR, targetFile)
|
||||
|
||||
// Handle different file types
|
||||
if (file.name.endsWith('.json')) {
|
||||
const data = JSON.parse(buffer.toString())
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
|
||||
} else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
|
||||
const workbook = XLSX.read(buffer, { type: 'buffer' })
|
||||
const sheetName = workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[sheetName]
|
||||
const data = XLSX.utils.sheet_to_json(worksheet)
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
|
||||
} else if (file.name.endsWith('.csv')) {
|
||||
const csv = buffer.toString()
|
||||
const lines = csv.split('\n')
|
||||
const headers = lines[0].split(',').map((h) => h.trim().replace(/^"|"$/g, ''))
|
||||
const data = lines.slice(1).map((line) => {
|
||||
const values = line.split(',').map((v) => v.trim().replace(/^"|"$/g, ''))
|
||||
return headers.reduce((obj, header, idx) => {
|
||||
obj[header] = values[idx] || ''
|
||||
return obj
|
||||
}, {} as Record<string, any>)
|
||||
})
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
|
||||
} else {
|
||||
return NextResponse.json({ error: 'Unsupported file type' }, { status: 400 })
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
filename: targetFile,
|
||||
records: Array.isArray(JSON.parse(fs.readFileSync(filePath, 'utf-8')))
|
||||
? JSON.parse(fs.readFileSync(filePath, 'utf-8')).length
|
||||
: 1,
|
||||
})
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to import file',
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
52
src/app/api/infrastructure/restore/route.ts
Normal file
52
src/app/api/infrastructure/restore/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as zlib from 'zlib'
|
||||
import { promisify } from 'util'
|
||||
|
||||
const gunzip = promisify(zlib.gunzip)
|
||||
|
||||
const DATA_DIR = path.join(process.cwd(), 'docs/infrastructure/data')
|
||||
const BACKUP_DIR = path.join(process.cwd(), 'docs/infrastructure/backups')
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { filename } = await request.json()
|
||||
|
||||
if (!filename) {
|
||||
return NextResponse.json({ error: 'Filename is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const backupPath = path.join(BACKUP_DIR, filename)
|
||||
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
return NextResponse.json({ error: 'Backup file not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
// Read and decompress backup
|
||||
const compressed = fs.readFileSync(backupPath)
|
||||
const decompressed = await gunzip(compressed)
|
||||
const backup = JSON.parse(decompressed.toString())
|
||||
|
||||
// Restore files
|
||||
for (const [file, data] of Object.entries(backup)) {
|
||||
const filePath = path.join(DATA_DIR, file)
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2))
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
filesRestored: Object.keys(backup).length,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to restore backup',
|
||||
message: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
122
src/app/certification/page.tsx
Normal file
122
src/app/certification/page.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Award, Book, CheckCircle, Clock } from 'lucide-react'
|
||||
|
||||
export default function CertificationPage() {
|
||||
const certifications = [
|
||||
{
|
||||
id: 'phoenix-admin',
|
||||
name: 'Phoenix Certified Administrator',
|
||||
level: 'Associate',
|
||||
duration: '3 months',
|
||||
description: 'Learn to manage and operate Phoenix infrastructure',
|
||||
skills: ['Infrastructure Management', 'Security', 'Monitoring'],
|
||||
},
|
||||
{
|
||||
id: 'phoenix-architect',
|
||||
name: 'Phoenix Certified Architect',
|
||||
level: 'Professional',
|
||||
duration: '6 months',
|
||||
description: 'Design and architect solutions on Phoenix platform',
|
||||
skills: ['Architecture Design', 'Best Practices', 'Scalability'],
|
||||
},
|
||||
{
|
||||
id: 'phoenix-developer',
|
||||
name: 'Phoenix Certified Developer',
|
||||
level: 'Associate',
|
||||
duration: '3 months',
|
||||
description: 'Build applications using Phoenix APIs and services',
|
||||
skills: ['API Development', 'SDKs', 'Integration'],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">Certification Program</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Validate your expertise with Phoenix certifications
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
|
||||
{certifications.map((cert) => (
|
||||
<Card key={cert.id} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Award className="h-8 w-8 text-phoenix-fire" />
|
||||
<span className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded">
|
||||
{cert.level}
|
||||
</span>
|
||||
</div>
|
||||
<CardTitle className="text-white">{cert.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{cert.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-400 mb-2">
|
||||
<Clock className="h-4 w-4" />
|
||||
<span>{cert.duration}</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-300 mb-2">Skills covered:</p>
|
||||
<ul className="space-y-1">
|
||||
{cert.skills.map((skill) => (
|
||||
<li key={skill} className="flex items-center gap-2 text-sm text-gray-400">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>{skill}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/certification/${cert.id}`}>Learn More</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Why Get Certified?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<Award className="h-6 w-6 text-phoenix-fire mb-2" />
|
||||
<h3 className="text-white font-semibold mb-2">Validate Skills</h3>
|
||||
<p className="text-gray-400 text-sm">
|
||||
Demonstrate your expertise to employers and clients
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Book className="h-6 w-6 text-sankofa-gold mb-2" />
|
||||
<h3 className="text-white font-semibold mb-2">Career Growth</h3>
|
||||
<p className="text-gray-400 text-sm">
|
||||
Advance your career with recognized credentials
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<CheckCircle className="h-6 w-6 text-neon-cyan mb-2" />
|
||||
<h3 className="text-white font-semibold mb-2">Stay Current</h3>
|
||||
<p className="text-gray-400 text-sm">
|
||||
Keep up with latest Phoenix features and best practices
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
171
src/app/community/page.tsx
Normal file
171
src/app/community/page.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { MessageSquare, Users, TrendingUp, Clock } from 'lucide-react'
|
||||
|
||||
export default function CommunityForumPage() {
|
||||
const categories = [
|
||||
{
|
||||
id: 'general',
|
||||
name: 'General Discussion',
|
||||
description: 'General questions and discussions',
|
||||
posts: 1250,
|
||||
latest: '2 hours ago',
|
||||
},
|
||||
{
|
||||
id: 'support',
|
||||
name: 'Support',
|
||||
description: 'Get help with technical issues',
|
||||
posts: 890,
|
||||
latest: '1 hour ago',
|
||||
},
|
||||
{
|
||||
id: 'announcements',
|
||||
name: 'Announcements',
|
||||
description: 'Product updates and news',
|
||||
posts: 45,
|
||||
latest: '1 day ago',
|
||||
},
|
||||
{
|
||||
id: 'showcase',
|
||||
name: 'Showcase',
|
||||
description: 'Share your projects and solutions',
|
||||
posts: 320,
|
||||
latest: '3 hours ago',
|
||||
},
|
||||
]
|
||||
|
||||
const recentPosts = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'How to optimize costs on Phoenix?',
|
||||
author: 'john_doe',
|
||||
category: 'Support',
|
||||
replies: 12,
|
||||
views: 245,
|
||||
time: '2 hours ago',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'New feature: Cost forecasting',
|
||||
author: 'sankofa_team',
|
||||
category: 'Announcements',
|
||||
replies: 8,
|
||||
views: 189,
|
||||
time: '5 hours ago',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Showcase: My Phoenix deployment',
|
||||
author: 'dev_user',
|
||||
category: 'Showcase',
|
||||
replies: 15,
|
||||
views: 312,
|
||||
time: '1 day ago',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">Community Forum</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Connect with other users, share knowledge, and get support
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12">
|
||||
{categories.map((category) => (
|
||||
<Card key={category.id} className="hover:border-phoenix-fire transition-colors cursor-pointer">
|
||||
<CardHeader>
|
||||
<MessageSquare className="h-8 w-8 text-phoenix-fire mb-2" />
|
||||
<CardTitle className="text-white">{category.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{category.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-between text-sm text-gray-400">
|
||||
<span>{category.posts} posts</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-4 w-4" />
|
||||
{category.latest}
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2">
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Recent Posts</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{recentPosts.map((post) => (
|
||||
<div
|
||||
key={post.id}
|
||||
className="p-4 bg-studio-black rounded-lg hover:bg-studio-medium transition-colors cursor-pointer"
|
||||
>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<h3 className="text-white font-semibold">{post.title}</h3>
|
||||
<span className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded">
|
||||
{post.category}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-sm text-gray-400">
|
||||
<span>by {post.author}</span>
|
||||
<span>{post.replies} replies</span>
|
||||
<span>{post.views} views</span>
|
||||
<span>{post.time}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Card className="bg-studio-dark border-studio-medium mb-6">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Users className="h-5 w-5 text-phoenix-fire" />
|
||||
Community Stats
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-400">Members</span>
|
||||
<span className="text-white font-semibold">12,450</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-400">Posts</span>
|
||||
<span className="text-white font-semibold">2,505</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-400">Online</span>
|
||||
<span className="text-white font-semibold">234</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Button variant="phoenix" className="w-full" asChild>
|
||||
<Link href="/community/new-post">Create New Post</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
63
src/app/company/accessibility/page.tsx
Normal file
63
src/app/company/accessibility/page.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Accessibility, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function AccessibilityPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Accessibility</h1>
|
||||
|
||||
<div className="space-y-8">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Accessibility className="h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle className="text-white">Accessibility Commitment</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Sankofa Phoenix is committed to making our platform accessible to all users.
|
||||
We follow WCAG 2.1 Level AA guidelines and continuously work to improve accessibility.
|
||||
</p>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>WCAG 2.1 Level AA compliant</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Keyboard navigation support</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Screen reader compatible</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>High contrast mode support</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Feedback</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
We welcome feedback on accessibility. If you encounter any accessibility issues,
|
||||
please contact our support team.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
67
src/app/company/compliance/page.tsx
Normal file
67
src/app/company/compliance/page.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Shield, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function CompliancePage() {
|
||||
const complianceFrameworks = [
|
||||
{ name: 'SOC 2 Type II', status: 'Certified', description: 'Security, availability, and confidentiality controls' },
|
||||
{ name: 'ISO 27001', status: 'Certified', description: 'Information security management system' },
|
||||
{ name: 'GDPR', status: 'Compliant', description: 'European data protection regulation' },
|
||||
{ name: 'HIPAA', status: 'Ready', description: 'Healthcare data protection (when applicable)' },
|
||||
{ name: 'PCI-DSS', status: 'Compliant', description: 'Payment card industry data security' },
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Compliance</h1>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Shield className="h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle className="text-white">Regulatory Compliance</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-6">
|
||||
Sankofa Phoenix maintains compliance with major regulatory frameworks and industry
|
||||
standards to meet enterprise and government requirements.
|
||||
</p>
|
||||
|
||||
<div className="space-y-4">
|
||||
{complianceFrameworks.map((framework) => (
|
||||
<div key={framework.name} className="p-4 bg-studio-dark rounded-lg">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3 className="text-lg font-semibold text-white">{framework.name}</h3>
|
||||
<span className="px-3 py-1 bg-green-500/20 text-green-400 text-xs font-semibold rounded-full">
|
||||
{framework.status}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-400">{framework.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Compliance Certifications</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
We undergo regular audits and assessments to maintain our compliance certifications.
|
||||
Certificates and audit reports are available upon request for enterprise customers.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
80
src/app/company/privacy/page.tsx
Normal file
80
src/app/company/privacy/page.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Lock, Eye, FileText, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function PrivacyPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Privacy</h1>
|
||||
|
||||
<div className="space-y-8">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Lock className="h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle className="text-white">Data Privacy & Sovereignty</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Sankofa Phoenix is committed to protecting your privacy and ensuring data sovereignty.
|
||||
We implement privacy by design principles and comply with global privacy regulations.
|
||||
</p>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>GDPR compliant</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Data residency controls</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Right to deletion</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Privacy by design</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Eye className="h-8 w-8 text-sankofa-gold" />
|
||||
<CardTitle className="text-white">Transparency</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
We are transparent about how we collect, use, and protect your data. Our privacy
|
||||
policy clearly outlines our data handling practices.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<FileText className="h-8 w-8 text-neon-cyan" />
|
||||
<CardTitle className="text-white">Privacy Policy</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
For detailed information about our privacy practices, please review our Privacy Policy.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
82
src/app/company/security/page.tsx
Normal file
82
src/app/company/security/page.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Shield, Lock, Eye, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function SecurityPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Security</h1>
|
||||
|
||||
<div className="space-y-8">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Shield className="h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle className="text-white">Enterprise-Grade Security</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Sankofa Phoenix is built with security as a foundational principle. Our infrastructure
|
||||
implements defense-in-depth strategies, zero-trust networking, and comprehensive
|
||||
security monitoring.
|
||||
</p>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>SOC 2 Type II certified</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>ISO 27001 compliant</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>Zero Trust architecture</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="h-5 w-5 text-green-400 mt-0.5" />
|
||||
<span>End-to-end encryption</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Lock className="h-8 w-8 text-sankofa-gold" />
|
||||
<CardTitle className="text-white">Data Protection</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
All data is encrypted at rest and in transit using industry-standard encryption
|
||||
algorithms. We implement comprehensive access controls and audit logging.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Eye className="h-8 w-8 text-neon-cyan" />
|
||||
<CardTitle className="text-white">Security Monitoring</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Continuous security monitoring, threat detection, and incident response capabilities
|
||||
ensure rapid detection and mitigation of security threats.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
156
src/app/company/trust/page.tsx
Normal file
156
src/app/company/trust/page.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Shield, Lock, FileCheck, Globe, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function TrustPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Trust & Compliance
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Enterprise-grade security, compliance, and data sovereignty
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Compliance Standards */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Compliance & Certifications
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>DoD/MilSpec Compliance</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">
|
||||
STIG-compliant infrastructure with security hardening and audit controls.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Security Technical Implementation Guides (STIG)</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>RMF authorization ready</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Lock className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Data Sovereignty</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">
|
||||
Complete control over data location, access, and governance.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Regional data residency controls</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>No vendor lock-in</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<FileCheck className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Audit & Reporting</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">
|
||||
Comprehensive audit logging and compliance reporting.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Immutable audit logs</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-4 w-4 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Compliance dashboards</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Security Features */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Security Features
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Sovereign Identity</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Keycloak-based identity management with zero Azure dependencies.
|
||||
Complete control over authentication, authorization, and user management.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Multi-factor authentication (MFA)</li>
|
||||
<li>• SSO integration (SAML, OIDC)</li>
|
||||
<li>• Role-based access control (RBAC)</li>
|
||||
<li>• Identity federation</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Zero Trust Architecture</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Every request is verified, every connection is encrypted, and access is
|
||||
granted on a least-privilege basis.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Network segmentation</li>
|
||||
<li>• End-to-end encryption</li>
|
||||
<li>• Continuous verification</li>
|
||||
<li>• Threat detection and response</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Questions About Compliance?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Contact our compliance team for detailed information
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/support">Contact Support</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
249
src/app/developers/docs/api/graphql/page.tsx
Normal file
249
src/app/developers/docs/api/graphql/page.tsx
Normal file
@@ -0,0 +1,249 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Code, Book, Terminal, ExternalLink } from 'lucide-react'
|
||||
|
||||
export default function GraphQLAPIPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4 max-w-6xl">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-bold text-white mb-4">GraphQL API Reference</h1>
|
||||
<p className="text-xl text-gray-300">
|
||||
Complete reference for the Phoenix Nexus GraphQL API
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Quick Start */}
|
||||
<Card className="mb-8 border-phoenix-fire/50">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5 text-phoenix-fire" />
|
||||
Quick Start
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 mb-2">Endpoint</h3>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
https://api.sankofa.nexus/graphql
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 mb-2">Authentication</h3>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
Authorization: Bearer {'<token>'}
|
||||
</code>
|
||||
</div>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/portal/developers">
|
||||
Get API Key <ExternalLink className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Queries */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold text-white mb-6">Queries</h2>
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Get Resources</CardTitle>
|
||||
<CardDescription>Retrieve a list of resources</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`query GetResources($filter: ResourceFilter) {
|
||||
resources(filter: $filter) {
|
||||
id
|
||||
name
|
||||
type
|
||||
status
|
||||
site {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Get Current User</CardTitle>
|
||||
<CardDescription>Get authenticated user information</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`query GetMe {
|
||||
me {
|
||||
id
|
||||
email
|
||||
name
|
||||
role
|
||||
tenant {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Get Tenants</CardTitle>
|
||||
<CardDescription>List all tenants (admin only)</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`query GetTenants {
|
||||
tenants {
|
||||
id
|
||||
name
|
||||
status
|
||||
createdAt
|
||||
quotas {
|
||||
compute
|
||||
storage
|
||||
network
|
||||
}
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Mutations */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold text-white mb-6">Mutations</h2>
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Create Resource</CardTitle>
|
||||
<CardDescription>Create a new resource</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`mutation CreateResource($input: CreateResourceInput!) {
|
||||
createResource(input: $input) {
|
||||
id
|
||||
name
|
||||
type
|
||||
status
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Create Tenant</CardTitle>
|
||||
<CardDescription>Create a new tenant (admin only)</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`mutation CreateTenant($input: CreateTenantInput!) {
|
||||
createTenant(input: $input) {
|
||||
id
|
||||
name
|
||||
status
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Types */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold text-white mb-6">Types</h2>
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Resource</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`type Resource {
|
||||
id: ID!
|
||||
name: String!
|
||||
type: ResourceType!
|
||||
status: ResourceStatus!
|
||||
site: Site
|
||||
tenant: Tenant
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Tenant</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`type Tenant {
|
||||
id: ID!
|
||||
name: String!
|
||||
status: TenantStatus!
|
||||
quotas: TenantQuotas!
|
||||
usage: TenantQuotaUsage!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Interactive Explorer */}
|
||||
<Card className="mb-8 border-sankofa-gold/50">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Code className="h-5 w-5 text-sankofa-gold" />
|
||||
Interactive API Explorer
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Try queries and mutations in the interactive GraphQL playground
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/portal/developers/explorer">
|
||||
Open API Explorer <ExternalLink className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Related Links */}
|
||||
<div className="flex gap-4">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/api/rest">REST API Reference →</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/guides/authentication">Authentication Guide →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
125
src/app/developers/docs/api/rest/page.tsx
Normal file
125
src/app/developers/docs/api/rest/page.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Code, Book, Terminal, ExternalLink } from 'lucide-react'
|
||||
|
||||
export default function RESTAPIPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4 max-w-6xl">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-bold text-white mb-4">REST API Reference</h1>
|
||||
<p className="text-xl text-gray-300">
|
||||
Complete reference for the Phoenix Nexus REST API
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Quick Start */}
|
||||
<Card className="mb-8 border-phoenix-fire/50">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5 text-phoenix-fire" />
|
||||
Quick Start
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 mb-2">Base URL</h3>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
https://api.sankofa.nexus/v1
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-400 mb-2">Authentication</h3>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
Authorization: Bearer {'<token>'}
|
||||
</code>
|
||||
</div>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/portal/developers">
|
||||
Get API Key <ExternalLink className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Endpoints */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold text-white mb-6">Endpoints</h2>
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Get Resources</CardTitle>
|
||||
<CardDescription>GET /v1/resources</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`GET /v1/resources
|
||||
Authorization: Bearer <token>
|
||||
|
||||
Response:
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "string",
|
||||
"type": "VM|CONTAINER|STORAGE|NETWORK",
|
||||
"status": "RUNNING|STOPPED|...",
|
||||
"createdAt": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Create Resource</CardTitle>
|
||||
<CardDescription>POST /v1/resources</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`POST /v1/resources
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "My Resource",
|
||||
"type": "VM",
|
||||
"siteId": "uuid"
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "My Resource",
|
||||
"status": "PROVISIONING",
|
||||
...
|
||||
}`}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Related Links */}
|
||||
<div className="flex gap-4">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/api/graphql">GraphQL API Reference →</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/guides/authentication">Authentication Guide →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
130
src/app/developers/docs/guides/authentication/page.tsx
Normal file
130
src/app/developers/docs/guides/authentication/page.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Shield, Key, Lock } from 'lucide-react'
|
||||
|
||||
export default function AuthenticationGuidePage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4 max-w-4xl">
|
||||
<div className="mb-12 text-center">
|
||||
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-phoenix-fire/20">
|
||||
<Shield className="h-8 w-8 text-phoenix-fire" />
|
||||
</div>
|
||||
<h1 className="text-5xl font-bold text-white mb-4">Authentication Guide</h1>
|
||||
<p className="text-xl text-gray-300">
|
||||
Learn how to authenticate with Phoenix Nexus APIs
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* API Keys */}
|
||||
<Card className="mb-8">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Key className="h-6 w-6 text-sankofa-gold" />
|
||||
<div>
|
||||
<CardTitle>API Key Authentication</CardTitle>
|
||||
<CardDescription>Simple and secure API key-based authentication</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="font-semibold text-white mb-2">1. Create an API Key</h3>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Navigate to the Developer Portal and create a new API key.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/portal/developers/keys">Create API Key →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-white mb-2">2. Use the API Key</h3>
|
||||
<p className="text-gray-300 mb-2">Include the API key in the Authorization header:</p>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`curl -X GET https://api.sankofa.nexus/graphql \\
|
||||
-H "Authorization: Bearer sk_live_your_key_here" \\
|
||||
-H "Content-Type: application/json"`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* JWT Tokens */}
|
||||
<Card className="mb-8">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<Lock className="h-6 w-6 text-neon-cyan" />
|
||||
<div>
|
||||
<CardTitle>JWT Token Authentication</CardTitle>
|
||||
<CardDescription>For user-based authentication</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="font-semibold text-white mb-2">1. Login</h3>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`mutation {
|
||||
login(email: "user@example.com", password: "password") {
|
||||
token
|
||||
user {
|
||||
id
|
||||
email
|
||||
name
|
||||
}
|
||||
}
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-white mb-2">2. Use the Token</h3>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`curl -X POST https://api.sankofa.nexus/graphql \\
|
||||
-H "Authorization: Bearer <jwt_token>" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{"query": "{ me { id email } }"}'`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Security Best Practices */}
|
||||
<Card className="mb-8 border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle>Security Best Practices</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Never commit API keys or tokens to version control</li>
|
||||
<li>• Use environment variables to store credentials</li>
|
||||
<li>• Rotate API keys regularly</li>
|
||||
<li>• Use HTTPS for all API requests</li>
|
||||
<li>• Implement token refresh for long-lived sessions</li>
|
||||
<li>• Monitor API key usage for suspicious activity</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Related Links */}
|
||||
<div className="flex gap-4">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/quickstart">Quick Start Guide →</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/api/graphql">GraphQL API →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
200
src/app/developers/docs/page.tsx
Normal file
200
src/app/developers/docs/page.tsx
Normal file
@@ -0,0 +1,200 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Book, Code, Terminal, GitBranch, Zap, FileText, Search } from 'lucide-react'
|
||||
|
||||
export default function DocsPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<div className="mb-8 flex items-center justify-center">
|
||||
<Search className="mr-4 h-8 w-8 text-gray-400" />
|
||||
<input
|
||||
type="search"
|
||||
placeholder="Search documentation..."
|
||||
className="w-full max-w-md rounded-lg border border-studio-medium bg-studio-dark px-4 py-3 text-white placeholder-gray-400 focus:border-phoenix-fire focus:outline-none focus:ring-1 focus:ring-phoenix-fire"
|
||||
/>
|
||||
</div>
|
||||
<h1 className="mb-6 text-center text-5xl font-bold text-white md:text-6xl">
|
||||
Documentation
|
||||
</h1>
|
||||
<p className="mb-8 text-center text-xl text-gray-300">
|
||||
Comprehensive guides, API references, and tutorials
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Start */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-8 text-3xl font-bold text-white">Getting Started</h2>
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs/quickstart">
|
||||
<CardHeader>
|
||||
<Zap className="mb-2 h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle>Quick Start</CardTitle>
|
||||
<CardDescription>
|
||||
Get up and running in 5 minutes
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs/installation">
|
||||
<CardHeader>
|
||||
<Terminal className="mb-2 h-8 w-8 text-sankofa-gold" />
|
||||
<CardTitle>Installation</CardTitle>
|
||||
<CardDescription>
|
||||
Install and configure Phoenix Nexus
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs/concepts">
|
||||
<CardHeader>
|
||||
<Book className="mb-2 h-8 w-8 text-neon-cyan" />
|
||||
<CardTitle>Core Concepts</CardTitle>
|
||||
<CardDescription>
|
||||
Understand the architecture
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Documentation Sections */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-8 text-3xl font-bold text-white">Documentation</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<Code className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">API Reference</h3>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li>
|
||||
<Link href="/developers/docs/api/graphql" className="hover:text-phoenix-fire">
|
||||
GraphQL API →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/api/rest" className="hover:text-phoenix-fire">
|
||||
REST APIs →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/api/websocket" className="hover:text-phoenix-fire">
|
||||
WebSocket APIs →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/api/authentication" className="hover:text-phoenix-fire">
|
||||
Authentication →
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FileText className="mb-4 h-8 w-8 text-sankofa-gold" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Guides</h3>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li>
|
||||
<Link href="/developers/docs/guides/architecture" className="hover:text-sankofa-gold">
|
||||
Architecture Guides →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/guides/security" className="hover:text-sankofa-gold">
|
||||
Security Guides →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/guides/compliance" className="hover:text-sankofa-gold">
|
||||
Compliance Guides →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/guides/best-practices" className="hover:text-sankofa-gold">
|
||||
Best Practices →
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Book className="mb-4 h-8 w-8 text-neon-cyan" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Tutorials</h3>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li>
|
||||
<Link href="/developers/docs/tutorials/first-app" className="hover:text-neon-cyan">
|
||||
Build Your First App →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/tutorials/multi-tenancy" className="hover:text-neon-cyan">
|
||||
Multi-Tenancy Setup →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/tutorials/integration" className="hover:text-neon-cyan">
|
||||
Integration Examples →
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<GitBranch className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">SDKs & Tools</h3>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li>
|
||||
<Link href="/developers/docs/sdks/cli" className="hover:text-phoenix-fire">
|
||||
CLI Documentation →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/sdks/typescript" className="hover:text-phoenix-fire">
|
||||
TypeScript SDK →
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/developers/docs/sdks/terraform" className="hover:text-phoenix-fire">
|
||||
Terraform Provider →
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Need More Help?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Access the developer portal for API keys and test environments
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/developers">Developer Portal</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
238
src/app/developers/docs/quickstart/page.tsx
Normal file
238
src/app/developers/docs/quickstart/page.tsx
Normal file
@@ -0,0 +1,238 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { CheckCircle, Code, Key, Terminal, ArrowRight } from 'lucide-react'
|
||||
|
||||
export default function QuickStartPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4 max-w-4xl">
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="text-5xl font-bold text-white mb-4">Quick Start Guide</h1>
|
||||
<p className="text-xl text-gray-300">
|
||||
Get up and running with Phoenix Nexus Cloud in 5 minutes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Steps */}
|
||||
<div className="space-y-8">
|
||||
{/* Step 1 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-phoenix-fire text-white font-bold">
|
||||
1
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Create an Account</CardTitle>
|
||||
<CardDescription>Sign up for Phoenix Nexus Cloud</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-300">
|
||||
If you don't have an account yet, create one to get started.
|
||||
</p>
|
||||
<Button variant="phoenix" asChild>
|
||||
<Link href="/portal/get-started">
|
||||
Get Started <ArrowRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Step 2 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-sankofa-gold text-studio-black font-bold">
|
||||
2
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Get Your API Key</CardTitle>
|
||||
<CardDescription>Generate an API key from the Developer Portal</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-300">
|
||||
Navigate to the Developer Portal and create your first API key.
|
||||
</p>
|
||||
<ol className="list-decimal list-inside space-y-2 text-gray-300">
|
||||
<li>Go to Developer Portal</li>
|
||||
<li>Click "Create API Key"</li>
|
||||
<li>Give it a descriptive name</li>
|
||||
<li>Copy the key (you won't see it again!)</li>
|
||||
</ol>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/portal/developers/keys">
|
||||
<Key className="mr-2 h-4 w-4" />
|
||||
Manage API Keys
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Step 3 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-neon-cyan text-studio-black font-bold">
|
||||
3
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Install the CLI</CardTitle>
|
||||
<CardDescription>Install the Phoenix Nexus CLI tool</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-300">
|
||||
Install the CLI using your preferred package manager:
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-gray-400 mb-1">npm</p>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
npm install -g @sankofa/phoenix-cli
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-gray-400 mb-1">pnpm</p>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
pnpm add -g @sankofa/phoenix-cli
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Step 4 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-phoenix-fire text-white font-bold">
|
||||
4
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Authenticate</CardTitle>
|
||||
<CardDescription>Configure the CLI with your API key</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-300">
|
||||
Set your API key as an environment variable or use the login command:
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-gray-400 mb-1">Environment Variable</p>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
export PHOENIX_API_KEY=sk_live_your_key_here
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-gray-400 mb-1">Or use login</p>
|
||||
<code className="block rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
phoenix login
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Step 5 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-sankofa-gold text-studio-black font-bold">
|
||||
5
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Make Your First API Call</CardTitle>
|
||||
<CardDescription>Test the connection with a simple query</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-300">
|
||||
Test your setup with a simple GraphQL query:
|
||||
</p>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`phoenix query '
|
||||
query {
|
||||
me {
|
||||
id
|
||||
email
|
||||
name
|
||||
}
|
||||
}
|
||||
'`}
|
||||
</pre>
|
||||
<p className="text-sm text-gray-400">
|
||||
Or use curl to make a direct HTTP request:
|
||||
</p>
|
||||
<pre className="rounded bg-studio-dark p-4 text-sm text-white overflow-x-auto">
|
||||
{`curl -X POST https://api.sankofa.nexus/graphql \\
|
||||
-H "Authorization: Bearer $PHOENIX_API_KEY" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{"query": "{ me { id email name } }"}'`}
|
||||
</pre>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Next Steps */}
|
||||
<Card className="mt-12 border-phoenix-fire/50">
|
||||
<CardHeader>
|
||||
<CardTitle>Next Steps</CardTitle>
|
||||
<CardDescription>Continue your journey with Phoenix Nexus</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="mt-1 h-5 w-5 text-phoenix-fire flex-shrink-0" />
|
||||
<div>
|
||||
<h4 className="font-semibold text-white mb-1">Read the API Reference</h4>
|
||||
<p className="text-sm text-gray-400 mb-2">
|
||||
Learn about all available queries and mutations
|
||||
</p>
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link href="/developers/docs/api/graphql">API Reference →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<CheckCircle className="mt-1 h-5 w-5 text-sankofa-gold flex-shrink-0" />
|
||||
<div>
|
||||
<h4 className="font-semibold text-white mb-1">Explore Examples</h4>
|
||||
<p className="text-sm text-gray-400 mb-2">
|
||||
See real-world integration examples
|
||||
</p>
|
||||
<Button variant="outline" size="sm" asChild>
|
||||
<Link href="/developers/docs/tutorials">Tutorials →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
105
src/app/developers/docs/tutorials/page.tsx
Normal file
105
src/app/developers/docs/tutorials/page.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { BookOpen, Code, Rocket, Zap } from 'lucide-react'
|
||||
|
||||
export default function TutorialsPage() {
|
||||
const tutorials = [
|
||||
{
|
||||
title: 'Getting Started with Phoenix Nexus',
|
||||
description: 'Build your first application using the Phoenix Nexus API',
|
||||
icon: Rocket,
|
||||
href: '/developers/docs/tutorials/getting-started',
|
||||
level: 'Beginner',
|
||||
},
|
||||
{
|
||||
title: 'Building a Multi-Tenant Application',
|
||||
description: 'Learn how to leverage multi-tenancy in your applications',
|
||||
icon: Code,
|
||||
href: '/developers/docs/tutorials/multi-tenant',
|
||||
level: 'Intermediate',
|
||||
},
|
||||
{
|
||||
title: 'Real-Time Resource Monitoring',
|
||||
description: 'Implement real-time monitoring with GraphQL subscriptions',
|
||||
icon: Zap,
|
||||
href: '/developers/docs/tutorials/realtime-monitoring',
|
||||
level: 'Advanced',
|
||||
},
|
||||
{
|
||||
title: 'Integrating with Keycloak SSO',
|
||||
description: 'Add single sign-on to your application',
|
||||
icon: BookOpen,
|
||||
href: '/developers/docs/tutorials/keycloak-sso',
|
||||
level: 'Intermediate',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4 max-w-6xl">
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="text-5xl font-bold text-white mb-4">Tutorials</h1>
|
||||
<p className="text-xl text-gray-300">
|
||||
Step-by-step guides to help you build with Phoenix Nexus
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
{tutorials.map((tutorial) => {
|
||||
const Icon = tutorial.icon
|
||||
return (
|
||||
<Card key={tutorial.href} className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="rounded-lg bg-phoenix-fire/20 p-3">
|
||||
<Icon className="h-6 w-6 text-phoenix-fire" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<CardTitle>{tutorial.title}</CardTitle>
|
||||
<span className="rounded-full bg-studio-medium px-2 py-1 text-xs text-gray-400">
|
||||
{tutorial.level}
|
||||
</span>
|
||||
</div>
|
||||
<CardDescription>{tutorial.description}</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href={tutorial.href}>Start Tutorial →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<Card className="mt-12 border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle>More Resources</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/api/graphql">API Reference</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/quickstart">Quick Start</Link>
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/guides/authentication">Authentication</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
182
src/app/developers/page.tsx
Normal file
182
src/app/developers/page.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Code, Book, Key, Terminal, Zap, GitBranch } from 'lucide-react'
|
||||
|
||||
export default function DevelopersPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Developer Resources
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Build on Sankofa's Phoenix Nexus Cloud with comprehensive APIs, SDKs, and documentation
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/developers/docs">View Documentation</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/portal/developers">Developer Portal</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Links */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Get Started
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs">
|
||||
<CardHeader>
|
||||
<Book className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Documentation</CardTitle>
|
||||
<CardDescription>
|
||||
API references, guides, tutorials, and architecture blueprints
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers">
|
||||
<CardHeader>
|
||||
<Key className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Developer Portal</CardTitle>
|
||||
<CardDescription>
|
||||
API keys, test environments, logs, and developer tools
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/quickstart">
|
||||
<CardHeader>
|
||||
<Zap className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Quick Start</CardTitle>
|
||||
<CardDescription>
|
||||
Get up and running in minutes with our step-by-step guides
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Developer Tools */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Developer Tools & Resources
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<Code className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">GraphQL API</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Powerful GraphQL API with real-time subscriptions, comprehensive type system,
|
||||
and built-in authentication.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Interactive API explorer</li>
|
||||
<li>• TypeScript SDK</li>
|
||||
<li>• WebSocket subscriptions</li>
|
||||
<li>• Rate limiting and quotas</li>
|
||||
</ul>
|
||||
<Button variant="outline" className="mt-4" asChild>
|
||||
<Link href="/developers/docs/api">API Reference →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Terminal className="mb-4 h-8 w-8 text-sankofa-gold" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">CLI & SDKs</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Command-line tools and SDKs for popular languages to integrate Phoenix Nexus
|
||||
into your workflow.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Phoenix CLI (Node.js, Python, Go)</li>
|
||||
<li>• Terraform provider</li>
|
||||
<li>• Kubernetes operators</li>
|
||||
<li>• CI/CD integrations</li>
|
||||
</ul>
|
||||
<Button variant="outline" className="mt-4" asChild>
|
||||
<Link href="/developers/docs/sdks">View SDKs →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<GitBranch className="mb-4 h-8 w-8 text-neon-cyan" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">GitOps & Infrastructure</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Infrastructure as Code with Crossplane, ArgoCD, and GitOps workflows for
|
||||
declarative infrastructure management.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Crossplane providers</li>
|
||||
<li>• ArgoCD integration</li>
|
||||
<li>• GitOps templates</li>
|
||||
<li>• Infrastructure blueprints</li>
|
||||
</ul>
|
||||
<Button variant="outline" className="mt-4" asChild>
|
||||
<Link href="/developers/docs/gitops">GitOps Guide →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Zap className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Test Environments</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Sandbox environments for testing and development, with instant provisioning
|
||||
and automatic cleanup.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Free tier for development</li>
|
||||
<li>• Isolated test environments</li>
|
||||
<li>• Pre-configured templates</li>
|
||||
<li>• Integration testing tools</li>
|
||||
</ul>
|
||||
<Button variant="outline" className="mt-4" asChild>
|
||||
<Link href="/portal/developers">Get API Keys →</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Build?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Start building on sovereign cloud infrastructure today
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/developers">Access Developer Portal</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/developers/docs">Read Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
131
src/app/docs/api/graphql/page.tsx
Normal file
131
src/app/docs/api/graphql/page.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
'use client'
|
||||
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { useState } from 'react'
|
||||
import { Play, Code, Book } from 'lucide-react'
|
||||
|
||||
export default function GraphQLExplorerPage() {
|
||||
const [query, setQuery] = useState(`query {
|
||||
resources {
|
||||
id
|
||||
name
|
||||
type
|
||||
status
|
||||
}
|
||||
}`)
|
||||
const [variables, setVariables] = useState('{}')
|
||||
const [response, setResponse] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const executeQuery = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
// In production, this would call the actual GraphQL API
|
||||
const res = await fetch('/api/graphql', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ query, variables: JSON.parse(variables) }),
|
||||
})
|
||||
const data = await res.json()
|
||||
setResponse(JSON.stringify(data, null, 2))
|
||||
} catch (error) {
|
||||
setResponse(JSON.stringify({ error: error.message }, null, 2))
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-8">
|
||||
<h1 className="mb-4 text-4xl font-bold text-white">GraphQL API Explorer</h1>
|
||||
<p className="text-gray-400">
|
||||
Interactive GraphQL API explorer with live query execution and schema documentation
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Code className="h-5 w-5 text-phoenix-fire" />
|
||||
Query Editor
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<textarea
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
className="w-full h-64 p-4 bg-studio-black border border-studio-medium rounded text-white font-mono text-sm"
|
||||
placeholder="Enter your GraphQL query..."
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Code className="h-5 w-5 text-sankofa-gold" />
|
||||
Variables (JSON)
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<textarea
|
||||
value={variables}
|
||||
onChange={(e) => setVariables(e.target.value)}
|
||||
className="w-full h-64 p-4 bg-studio-black border border-studio-medium rounded text-white font-mono text-sm"
|
||||
placeholder='{"key": "value"}'
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<button
|
||||
onClick={executeQuery}
|
||||
disabled={loading}
|
||||
className="px-6 py-3 bg-phoenix-fire text-white rounded-lg hover:bg-phoenix-fire/90 transition-colors disabled:opacity-50 flex items-center gap-2"
|
||||
>
|
||||
<Play className="h-4 w-4" />
|
||||
{loading ? 'Executing...' : 'Execute Query'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{response && (
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Book className="h-5 w-5 text-neon-cyan" />
|
||||
Response
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="p-4 bg-studio-black border border-studio-medium rounded text-white font-mono text-sm overflow-auto">
|
||||
{response}
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card className="mt-6 bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Schema Documentation</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Explore the GraphQL schema to discover available queries, mutations, and types.
|
||||
</p>
|
||||
<button className="px-4 py-2 bg-studio-medium text-white rounded hover:bg-studio-medium/80 transition-colors">
|
||||
View Schema Documentation →
|
||||
</button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
73
src/app/docs/api/page.tsx
Normal file
73
src/app/docs/api/page.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export default function APIDocsPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">API Reference</h1>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">GraphQL API</CardTitle>
|
||||
<CardDescription>
|
||||
Comprehensive GraphQL API with real-time subscriptions
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Our GraphQL API provides a flexible, type-safe interface for querying and mutating
|
||||
infrastructure resources, with built-in authentication and real-time subscriptions.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/api/graphql">View GraphQL Schema →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">REST API</CardTitle>
|
||||
<CardDescription>
|
||||
Traditional REST endpoints for resource management
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
RESTful API endpoints following standard HTTP conventions for managing
|
||||
resources, with comprehensive OpenAPI documentation.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/api/rest">View REST API Docs →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">SDKs</CardTitle>
|
||||
<CardDescription>
|
||||
Client libraries for popular programming languages
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Official SDKs for TypeScript, Python, Go, and more, with type definitions
|
||||
and comprehensive examples.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/api/sdks">View SDK Documentation →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
73
src/app/docs/governance/page.tsx
Normal file
73
src/app/docs/governance/page.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export default function GovernancePage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Governance & Architecture</h1>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Architecture Blueprints</CardTitle>
|
||||
<CardDescription>
|
||||
Reference architectures for common patterns
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Pre-built architecture blueprints for common deployment patterns,
|
||||
including multi-region, high-availability, and disaster recovery setups.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/governance/blueprints">View Blueprints →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Compliance Guides</CardTitle>
|
||||
<CardDescription>
|
||||
Compliance frameworks and requirements
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Guides for meeting compliance requirements including SOC 2, ISO 27001,
|
||||
GDPR, HIPAA, and other regulatory frameworks.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/governance/compliance">View Compliance Guides →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Security Frameworks</CardTitle>
|
||||
<CardDescription>
|
||||
Security best practices and frameworks
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Security frameworks, threat modeling, and best practices for securing
|
||||
your infrastructure and applications.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/governance/security">View Security Frameworks →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
73
src/app/docs/guides/page.tsx
Normal file
73
src/app/docs/guides/page.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export default function GuidesPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Conceptual Guides</h1>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Architecture Overview</CardTitle>
|
||||
<CardDescription>
|
||||
Understanding the Sankofa Phoenix architecture
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Learn about the multi-tier architecture, global deployment model, and
|
||||
how components work together to deliver sovereign cloud infrastructure.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/guides/architecture">Read Architecture Guide →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Well-Architected Framework</CardTitle>
|
||||
<CardDescription>
|
||||
Best practices for building on Sankofa Phoenix
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Guidelines for building reliable, secure, performant, and cost-effective
|
||||
applications on the Phoenix platform.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/guides/well-architected">View Framework →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Best Practices</CardTitle>
|
||||
<CardDescription>
|
||||
Recommended patterns and practices
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Learn from real-world examples and recommended patterns for common
|
||||
use cases and scenarios.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/guides/best-practices">View Best Practices →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
134
src/app/docs/page.tsx
Normal file
134
src/app/docs/page.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Book, Code, GraduationCap, Shield, ArrowRight } from 'lucide-react'
|
||||
|
||||
export default function DocsPage() {
|
||||
const docSections = [
|
||||
{
|
||||
title: 'API Reference',
|
||||
description: 'REST API documentation, GraphQL schema, and SDK references',
|
||||
icon: Code,
|
||||
href: '/docs/api',
|
||||
categories: ['REST API', 'GraphQL', 'SDKs'],
|
||||
},
|
||||
{
|
||||
title: 'Conceptual Guides',
|
||||
description: 'Architecture overview, Well-Architected Framework, and best practices',
|
||||
icon: Book,
|
||||
href: '/docs/guides',
|
||||
categories: ['Architecture', 'Best Practices', 'Framework'],
|
||||
},
|
||||
{
|
||||
title: 'Tutorials & Quickstarts',
|
||||
description: 'Getting started guides, step-by-step tutorials, and sample code',
|
||||
icon: GraduationCap,
|
||||
href: '/docs/tutorials',
|
||||
categories: ['Quickstarts', 'Tutorials', 'Samples'],
|
||||
},
|
||||
{
|
||||
title: 'Governance & Architecture',
|
||||
description: 'Architecture blueprints, compliance guides, and security frameworks',
|
||||
icon: Shield,
|
||||
href: '/docs/governance',
|
||||
categories: ['Blueprints', 'Compliance', 'Security'],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero Section */}
|
||||
<section className="relative flex min-h-[40vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Documentation & Learning
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Comprehensive guides, tutorials, and references for building on Sankofa Phoenix
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Documentation Sections */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
{docSections.map((section) => {
|
||||
const Icon = section.icon
|
||||
return (
|
||||
<Card key={section.href} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Icon className="h-8 w-8 text-phoenix-fire" />
|
||||
<CardTitle className="text-2xl text-white">{section.title}</CardTitle>
|
||||
</div>
|
||||
<CardDescription className="text-gray-400">
|
||||
{section.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-wrap gap-2 mb-4">
|
||||
{section.categories.map((category) => (
|
||||
<span
|
||||
key={category}
|
||||
className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded"
|
||||
>
|
||||
{category}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={section.href}>
|
||||
Explore {section.title}
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Links */}
|
||||
<section className="py-16 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h2 className="mb-8 text-center text-3xl font-bold text-white">
|
||||
Quick Links
|
||||
</h2>
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<Link
|
||||
href="/docs/api/graphql"
|
||||
className="p-4 bg-studio-black rounded-lg hover:border-phoenix-fire border border-studio-medium transition-colors"
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-white mb-2">GraphQL API</h3>
|
||||
<p className="text-sm text-gray-400">Interactive API explorer</p>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs/tutorials/getting-started"
|
||||
className="p-4 bg-studio-black rounded-lg hover:border-phoenix-fire border border-studio-medium transition-colors"
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-white mb-2">Getting Started</h3>
|
||||
<p className="text-sm text-gray-400">Your first deployment</p>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs/guides/architecture"
|
||||
className="p-4 bg-studio-black rounded-lg hover:border-phoenix-fire border border-studio-medium transition-colors"
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-white mb-2">Architecture</h3>
|
||||
<p className="text-sm text-gray-400">System architecture overview</p>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
73
src/app/docs/tutorials/page.tsx
Normal file
73
src/app/docs/tutorials/page.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
export default function TutorialsPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="mb-8 text-4xl font-bold text-white">Tutorials & Quickstarts</h1>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Getting Started</CardTitle>
|
||||
<CardDescription>
|
||||
Your first deployment on Sankofa Phoenix
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Get up and running in minutes with our step-by-step getting started guide.
|
||||
Deploy your first application and learn the basics.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/tutorials/getting-started">Start Tutorial →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Step-by-Step Tutorials</CardTitle>
|
||||
<CardDescription>
|
||||
Comprehensive tutorials for common scenarios
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Follow along with detailed tutorials covering infrastructure provisioning,
|
||||
application deployment, monitoring, and more.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/tutorials/step-by-step">Browse Tutorials →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Sample Code</CardTitle>
|
||||
<CardDescription>
|
||||
Ready-to-use code samples and examples
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-4">
|
||||
Explore sample code, configuration files, and complete examples that you
|
||||
can use as starting points for your projects.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/docs/tutorials/samples">View Samples →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
260
src/app/enterprise/page.tsx
Normal file
260
src/app/enterprise/page.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Shield, Lock, Globe, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function EnterprisePage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero Section */}
|
||||
<section className="relative flex min-h-[60vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Enterprise & Government
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Sovereign cloud infrastructure built for enterprise scale and government compliance
|
||||
</p>
|
||||
|
||||
<p className="mb-12 text-lg text-gray-400">
|
||||
Trust, security, and compliance at the core of every deployment
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Contact Sales</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/company/trust">Learn About Trust</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Trust & Compliance Section */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Trust & Compliance
|
||||
</h2>
|
||||
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-phoenix-fire">Security</CardTitle>
|
||||
<CardDescription>
|
||||
Enterprise-grade security
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
SOC 2 Type II certified
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
ISO 27001 compliant
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
Zero Trust architecture
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
End-to-end encryption
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Lock className="mb-4 h-12 w-12 text-sankofa-gold" />
|
||||
<CardTitle className="text-sankofa-gold">Privacy</CardTitle>
|
||||
<CardDescription>
|
||||
Data sovereignty and privacy
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
GDPR compliant
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
Data residency controls
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
Right to deletion
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
Privacy by design
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Globe className="mb-4 h-12 w-12 text-neon-cyan" />
|
||||
<CardTitle className="text-neon-cyan">Compliance</CardTitle>
|
||||
<CardDescription>
|
||||
Regulatory compliance
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
HIPAA ready
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
PCI-DSS compliant
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
FedRAMP in progress
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
Regional compliance
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Sovereignty Messaging */}
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
True Technological Sovereignty
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Sankofa Phoenix delivers complete control over infrastructure, data, and destiny.
|
||||
No vendor lock-in. No dependencies on foreign cloud providers.
|
||||
Sovereign identity and self-determined policy frameworks.
|
||||
</p>
|
||||
<p className="text-lg text-gray-400">
|
||||
Built for organizations that require true sovereignty, cultural alignment,
|
||||
and infrastructure that honors identity while delivering world-class performance.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Case Studies / Use Cases */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Enterprise Use Cases
|
||||
</h2>
|
||||
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Government & Public Sector</CardTitle>
|
||||
<CardDescription>
|
||||
Sovereign infrastructure for government agencies
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Data residency and sovereignty requirements</li>
|
||||
<li>• Compliance with government regulations</li>
|
||||
<li>• Secure multi-agency collaboration</li>
|
||||
<li>• Disaster recovery and business continuity</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Financial Services</CardTitle>
|
||||
<CardDescription>
|
||||
Secure, compliant infrastructure for financial institutions
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• PCI-DSS compliant infrastructure</li>
|
||||
<li>• Real-time transaction processing</li>
|
||||
<li>• Regulatory reporting and compliance</li>
|
||||
<li>• High-availability and fault tolerance</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Healthcare & Life Sciences</CardTitle>
|
||||
<CardDescription>
|
||||
HIPAA-compliant infrastructure for healthcare organizations
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-gray-300">
|
||||
<li>• Protected health information (PHI) handling</li>
|
||||
<li>• HIPAA compliance and audit trails</li>
|
||||
<li>• Research data management</li>
|
||||
<li>• Interoperability and data exchange</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Global Enterprises</CardTitle>
|
||||
<CardDescription>
|
||||
Multi-region infrastructure for global operations
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• 325-region global deployment</li>
|
||||
<li>• Cultural intelligence and localization</li>
|
||||
<li>• Multi-tenant isolation</li>
|
||||
<li>• Enterprise-scale resource management</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Contact our enterprise sales team to discuss your requirements
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Contact Sales</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/company/trust">View Trust Center</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
|
||||
body {
|
||||
@apply bg-studio-black text-foreground;
|
||||
/* Cross-browser text size adjustment */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
@@ -34,6 +38,12 @@
|
||||
box-shadow: 0 0 20px rgba(0, 255, 209, 0.5);
|
||||
}
|
||||
|
||||
/* Cross-browser backdrop filter support */
|
||||
.backdrop-blur-safari {
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
@@ -56,5 +66,45 @@
|
||||
clip: auto;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* Chart container styles */
|
||||
.chart-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Status indicator colors */
|
||||
.status-pass {
|
||||
background-color: #00FF88;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.status-fail {
|
||||
background-color: #FF0040;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.status-warning {
|
||||
background-color: #FFB800;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Dynamic color utilities - use data attributes for dynamic colors */
|
||||
[data-pillar-color] {
|
||||
color: var(--pillar-color);
|
||||
}
|
||||
|
||||
[data-score-color] {
|
||||
color: var(--score-color);
|
||||
}
|
||||
|
||||
[data-health-color] {
|
||||
color: var(--health-color);
|
||||
}
|
||||
|
||||
[data-pillar-bg] {
|
||||
background-color: var(--pillar-bg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
13
src/app/infrastructure/docs/compliance/page.tsx
Normal file
13
src/app/infrastructure/docs/compliance/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ComplianceMapping } from '@/components/infrastructure/ComplianceMapping'
|
||||
import { InfrastructureErrorBoundary } from '@/components/infrastructure/InfrastructureErrorBoundary'
|
||||
|
||||
export default function CompliancePage() {
|
||||
return (
|
||||
<InfrastructureErrorBoundary>
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<ComplianceMapping />
|
||||
</div>
|
||||
</InfrastructureErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
13
src/app/infrastructure/docs/costs/page.tsx
Normal file
13
src/app/infrastructure/docs/costs/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { CostEstimates } from '@/components/infrastructure/CostEstimates'
|
||||
import { InfrastructureErrorBoundary } from '@/components/infrastructure/InfrastructureErrorBoundary'
|
||||
|
||||
export default function CostsPage() {
|
||||
return (
|
||||
<InfrastructureErrorBoundary>
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<CostEstimates />
|
||||
</div>
|
||||
</InfrastructureErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
20
src/app/infrastructure/docs/layout.tsx
Normal file
20
src/app/infrastructure/docs/layout.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { SkipLink, useKeyboardNavigation, FocusIndicator } from '@/components/infrastructure/AccessibilityEnhancements'
|
||||
|
||||
export default function InfrastructureLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
useKeyboardNavigation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<SkipLink />
|
||||
<FocusIndicator />
|
||||
<div id="main-content" className="min-h-screen">
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
13
src/app/infrastructure/docs/page.tsx
Normal file
13
src/app/infrastructure/docs/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { DocsDashboard } from '@/components/infrastructure/DocsDashboard'
|
||||
import { InfrastructureErrorBoundary } from '@/components/infrastructure/InfrastructureErrorBoundary'
|
||||
|
||||
export default function InfrastructureDocsPage() {
|
||||
return (
|
||||
<InfrastructureErrorBoundary>
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<DocsDashboard />
|
||||
</div>
|
||||
</InfrastructureErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
13
src/app/infrastructure/docs/timeline/page.tsx
Normal file
13
src/app/infrastructure/docs/timeline/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { DeploymentTimeline } from '@/components/infrastructure/DeploymentTimeline'
|
||||
import { InfrastructureErrorBoundary } from '@/components/infrastructure/InfrastructureErrorBoundary'
|
||||
|
||||
export default function TimelinePage() {
|
||||
return (
|
||||
<InfrastructureErrorBoundary>
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<DeploymentTimeline />
|
||||
</div>
|
||||
</InfrastructureErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
13
src/app/infrastructure/docs/topology/page.tsx
Normal file
13
src/app/infrastructure/docs/topology/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { NetworkTopologyDocs } from '@/components/infrastructure/NetworkTopologyDocs'
|
||||
import { InfrastructureErrorBoundary } from '@/components/infrastructure/InfrastructureErrorBoundary'
|
||||
|
||||
export default function TopologyPage() {
|
||||
return (
|
||||
<InfrastructureErrorBoundary>
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<NetworkTopologyDocs />
|
||||
</div>
|
||||
</InfrastructureErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Metadata } from 'next'
|
||||
import type { Metadata, Viewport } from 'next'
|
||||
import { Inter } from 'next/font/google'
|
||||
import './globals.css'
|
||||
import { Providers } from './providers'
|
||||
@@ -10,8 +10,19 @@ const inter = Inter({
|
||||
})
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Phoenix Sankofa Cloud',
|
||||
title: {
|
||||
default: "Sankofa's Phoenix Nexus Cloud",
|
||||
template: "%s | Sankofa's Phoenix Nexus Cloud",
|
||||
},
|
||||
description: 'The sovereign cloud born of fire and ancestral wisdom.',
|
||||
metadataBase: new URL(process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'),
|
||||
}
|
||||
|
||||
// Viewport configuration without maximum-scale and user-scalable for accessibility compliance
|
||||
export const viewport: Viewport = {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
// Note: maximum-scale and user-scalable removed per accessibility best practices
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function ManifestoPage() {
|
||||
<header className="border-b border-studio-medium bg-studio-dark">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
|
||||
<Link href="/" className="text-2xl font-bold text-white">
|
||||
Phoenix <span className="text-phoenix-fire">Sankofa</span> Cloud
|
||||
<span className="text-sankofa-gold">Sankofa's</span> Phoenix <span className="text-phoenix-fire">Nexus</span> Cloud
|
||||
</Link>
|
||||
<nav className="flex gap-4">
|
||||
<Link href="/" className="text-gray-400 hover:text-white">
|
||||
@@ -137,7 +137,10 @@ export default function ManifestoPage() {
|
||||
This is the Sankofa cycle. This is the Phoenix transformation.
|
||||
</p>
|
||||
<p className="text-center text-2xl font-bold text-phoenix-fire">
|
||||
This is Phoenix Sankofa Cloud.
|
||||
This is Sankofa.
|
||||
</p>
|
||||
<p className="text-center text-2xl font-bold text-phoenix-fire">
|
||||
This is Sankofa Phoenix.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
113
src/app/marketplace/api/page.tsx
Normal file
113
src/app/marketplace/api/page.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Globe, Star, TrendingUp } from 'lucide-react'
|
||||
|
||||
export default function APIMarketplacePage() {
|
||||
const apis = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Weather API',
|
||||
provider: 'WeatherCorp',
|
||||
description: 'Real-time weather data and forecasts',
|
||||
rating: 4.7,
|
||||
requests: '10M+',
|
||||
category: 'Data',
|
||||
pricing: 'Free tier available',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Payment Gateway',
|
||||
provider: 'PayFlow',
|
||||
description: 'Secure payment processing API',
|
||||
rating: 4.9,
|
||||
requests: '50M+',
|
||||
category: 'Payment',
|
||||
pricing: 'Pay per transaction',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'AI Image Processing',
|
||||
provider: 'VisionAI',
|
||||
description: 'Advanced image recognition and processing',
|
||||
rating: 4.6,
|
||||
requests: '5M+',
|
||||
category: 'AI/ML',
|
||||
pricing: 'Usage-based',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">API Marketplace</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Discover and integrate third-party APIs into your applications
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{apis.map((api) => (
|
||||
<Card key={api.id} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<Globe className="h-8 w-8 text-phoenix-fire" />
|
||||
<span className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded">
|
||||
{api.category}
|
||||
</span>
|
||||
</div>
|
||||
<CardTitle className="text-white">{api.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
by {api.provider}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">{api.description}</p>
|
||||
|
||||
<div className="space-y-2 mb-4">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-400">
|
||||
<Star className="h-4 w-4 text-yellow-400 fill-yellow-400" />
|
||||
<span>{api.rating}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-gray-400">
|
||||
<TrendingUp className="h-4 w-4" />
|
||||
<span>{api.requests} requests/month</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">{api.pricing}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" className="flex-1" asChild>
|
||||
<Link href={`/marketplace/api/${api.id}`}>
|
||||
View Docs
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="phoenix" asChild>
|
||||
<Link href={`/marketplace/api/${api.id}/subscribe`}>
|
||||
Subscribe
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Publish Your API</h2>
|
||||
<p className="mb-6 text-gray-400">
|
||||
Monetize your API and reach developers worldwide
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/developers/api/publish">Publish API</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
238
src/app/marketplace/deployments/[id]/page.tsx
Normal file
238
src/app/marketplace/deployments/[id]/page.tsx
Normal file
@@ -0,0 +1,238 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { ArrowLeft, Trash2, RefreshCw } from 'lucide-react'
|
||||
|
||||
async function fetchDeployment(id: string) {
|
||||
const response = await fetch('/api/graphql', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
query: `
|
||||
query GetDeployment($id: ID!) {
|
||||
deployment(id: $id) {
|
||||
id
|
||||
name
|
||||
status
|
||||
deploymentType
|
||||
region
|
||||
parameters
|
||||
outputs
|
||||
errorMessage
|
||||
createdAt
|
||||
startedAt
|
||||
completedAt
|
||||
logs(limit: 100) {
|
||||
id
|
||||
level
|
||||
message
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { id },
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
return data.data?.deployment
|
||||
}
|
||||
|
||||
export default function DeploymentDetailPage() {
|
||||
const params = useParams()
|
||||
const router = useRouter()
|
||||
const id = params.id as string
|
||||
|
||||
const { data: deployment, isLoading, refetch } = useQuery({
|
||||
queryKey: ['deployment', id],
|
||||
queryFn: () => fetchDeployment(id),
|
||||
refetchInterval: 5000,
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="animate-pulse space-y-4">
|
||||
<div className="h-8 bg-muted rounded w-1/3" />
|
||||
<div className="h-64 bg-muted rounded" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!deployment) {
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<p className="text-muted-foreground mb-4">Deployment not found</p>
|
||||
<Button onClick={() => router.push('/marketplace/deployments')}>
|
||||
Back to Deployments
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<Button variant="ghost" onClick={() => router.back()}>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Back
|
||||
</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={() => refetch()}>
|
||||
<RefreshCw className="mr-2 h-4 w-4" />
|
||||
Refresh
|
||||
</Button>
|
||||
<Button variant="destructive">
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<h1 className="text-4xl font-bold mb-2">{deployment.name}</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge>{deployment.status}</Badge>
|
||||
<Badge variant="outline">{deployment.deploymentType}</Badge>
|
||||
{deployment.region && (
|
||||
<Badge variant="outline">Region: {deployment.region}</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="overview" className="space-y-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="logs">Logs</TabsTrigger>
|
||||
<TabsTrigger value="outputs">Outputs</TabsTrigger>
|
||||
<TabsTrigger value="parameters">Parameters</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Deployment Information</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Status:</span>
|
||||
<Badge>{deployment.status}</Badge>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Type:</span>
|
||||
<span>{deployment.deploymentType}</span>
|
||||
</div>
|
||||
{deployment.region && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Region:</span>
|
||||
<span>{deployment.region}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Created:</span>
|
||||
<span>{new Date(deployment.createdAt).toLocaleString()}</span>
|
||||
</div>
|
||||
{deployment.startedAt && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Started:</span>
|
||||
<span>{new Date(deployment.startedAt).toLocaleString()}</span>
|
||||
</div>
|
||||
)}
|
||||
{deployment.completedAt && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Completed:</span>
|
||||
<span>{new Date(deployment.completedAt).toLocaleString()}</span>
|
||||
</div>
|
||||
)}
|
||||
{deployment.errorMessage && (
|
||||
<div className="mt-4 p-4 bg-red-50 border border-red-200 rounded">
|
||||
<p className="text-sm font-medium text-red-800">Error:</p>
|
||||
<p className="text-sm text-red-600">{deployment.errorMessage}</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="logs">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Deployment Logs</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2 max-h-96 overflow-y-auto">
|
||||
{deployment.logs && deployment.logs.length > 0 ? (
|
||||
deployment.logs.map((log: any) => (
|
||||
<div
|
||||
key={log.id}
|
||||
className={`p-2 rounded text-sm font-mono ${
|
||||
log.level === 'ERROR'
|
||||
? 'bg-red-50 text-red-800'
|
||||
: log.level === 'WARN'
|
||||
? 'bg-yellow-50 text-yellow-800'
|
||||
: 'bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<span className="text-muted-foreground">
|
||||
[{new Date(log.createdAt).toLocaleTimeString()}] [{log.level}]
|
||||
</span>{' '}
|
||||
{log.message}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p className="text-muted-foreground">No logs available</p>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="outputs">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Deployment Outputs</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{deployment.outputs && Object.keys(deployment.outputs).length > 0 ? (
|
||||
<pre className="p-4 bg-muted rounded overflow-auto">
|
||||
{JSON.stringify(deployment.outputs, null, 2)}
|
||||
</pre>
|
||||
) : (
|
||||
<p className="text-muted-foreground">No outputs available</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="parameters">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Deployment Parameters</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{deployment.parameters && Object.keys(deployment.parameters).length > 0 ? (
|
||||
<pre className="p-4 bg-muted rounded overflow-auto">
|
||||
{JSON.stringify(deployment.parameters, null, 2)}
|
||||
</pre>
|
||||
) : (
|
||||
<p className="text-muted-foreground">No parameters available</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
145
src/app/marketplace/deployments/page.tsx
Normal file
145
src/app/marketplace/deployments/page.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Clock, CheckCircle, XCircle, Loader } from 'lucide-react'
|
||||
|
||||
async function fetchDeployments() {
|
||||
const response = await fetch('/api/graphql', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
query: `
|
||||
query GetDeployments {
|
||||
deployments {
|
||||
id
|
||||
name
|
||||
status
|
||||
deploymentType
|
||||
region
|
||||
createdAt
|
||||
completedAt
|
||||
}
|
||||
}
|
||||
`,
|
||||
}),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
return data.data?.deployments || []
|
||||
}
|
||||
|
||||
const STATUS_COLORS: Record<string, string> = {
|
||||
PENDING: 'bg-yellow-100 text-yellow-800',
|
||||
PROVISIONING: 'bg-blue-100 text-blue-800',
|
||||
DEPLOYING: 'bg-blue-100 text-blue-800',
|
||||
RUNNING: 'bg-green-100 text-green-800',
|
||||
FAILED: 'bg-red-100 text-red-800',
|
||||
STOPPED: 'bg-gray-100 text-gray-800',
|
||||
}
|
||||
|
||||
const STATUS_ICONS: Record<string, any> = {
|
||||
PENDING: Clock,
|
||||
PROVISIONING: Loader,
|
||||
DEPLOYING: Loader,
|
||||
RUNNING: CheckCircle,
|
||||
FAILED: XCircle,
|
||||
STOPPED: Clock,
|
||||
}
|
||||
|
||||
export default function DeploymentsPage() {
|
||||
const { data: deployments = [], isLoading } = useQuery({
|
||||
queryKey: ['deployments'],
|
||||
queryFn: fetchDeployments,
|
||||
refetchInterval: 5000, // Refresh every 5 seconds
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="animate-pulse space-y-4">
|
||||
<div className="h-8 bg-muted rounded w-1/3" />
|
||||
<div className="h-64 bg-muted rounded" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold mb-2">Deployments</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Monitor and manage your deployments
|
||||
</p>
|
||||
</div>
|
||||
<Link href="/marketplace">
|
||||
<Button>New Deployment</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{deployments.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<p className="text-muted-foreground mb-4">No deployments found</p>
|
||||
<Link href="/marketplace">
|
||||
<Button>Browse Marketplace</Button>
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{deployments.map((deployment: any) => {
|
||||
const StatusIcon = STATUS_ICONS[deployment.status] || Clock
|
||||
return (
|
||||
<Card key={deployment.id} className="hover:shadow-lg transition-shadow">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between">
|
||||
<CardTitle className="text-xl">
|
||||
<Link
|
||||
href={`/marketplace/deployments/${deployment.id}`}
|
||||
className="hover:underline"
|
||||
>
|
||||
{deployment.name}
|
||||
</Link>
|
||||
</CardTitle>
|
||||
<StatusIcon
|
||||
className={`h-5 w-5 ${
|
||||
deployment.status === 'RUNNING'
|
||||
? 'text-green-500'
|
||||
: deployment.status === 'FAILED'
|
||||
? 'text-red-500'
|
||||
: 'text-blue-500'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<CardDescription>
|
||||
{deployment.region && (
|
||||
<span className="mr-2">Region: {deployment.region}</span>
|
||||
)}
|
||||
<span>Type: {deployment.deploymentType}</span>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-between">
|
||||
<Badge className={STATUS_COLORS[deployment.status] || ''}>
|
||||
{deployment.status}
|
||||
</Badge>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{new Date(deployment.createdAt).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
113
src/app/marketplace/developers/page.tsx
Normal file
113
src/app/marketplace/developers/page.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Code, Star, Download, ExternalLink } from 'lucide-react'
|
||||
|
||||
export default function DeveloperMarketplacePage() {
|
||||
const tools = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Phoenix CLI',
|
||||
author: 'Sankofa Team',
|
||||
description: 'Command-line interface for managing Phoenix resources',
|
||||
rating: 4.9,
|
||||
downloads: 5000,
|
||||
category: 'CLI Tools',
|
||||
language: 'TypeScript',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Terraform Provider',
|
||||
author: 'Community',
|
||||
description: 'Terraform provider for infrastructure as code',
|
||||
rating: 4.7,
|
||||
downloads: 3200,
|
||||
category: 'IaC',
|
||||
language: 'Go',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Python SDK',
|
||||
author: 'Sankofa Team',
|
||||
description: 'Official Python SDK for Phoenix API',
|
||||
rating: 4.8,
|
||||
downloads: 2800,
|
||||
category: 'SDK',
|
||||
language: 'Python',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">Developer Marketplace</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Tools, libraries, and integrations built by the community
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{tools.map((tool) => (
|
||||
<Card key={tool.id} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<Code className="h-8 w-8 text-phoenix-fire" />
|
||||
<span className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded">
|
||||
{tool.category}
|
||||
</span>
|
||||
</div>
|
||||
<CardTitle className="text-white">{tool.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
by {tool.author}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">{tool.description}</p>
|
||||
|
||||
<div className="flex items-center gap-4 mb-4 text-sm text-gray-400">
|
||||
<div className="flex items-center gap-1">
|
||||
<Star className="h-4 w-4 text-yellow-400 fill-yellow-400" />
|
||||
<span>{tool.rating}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<Download className="h-4 w-4" />
|
||||
<span>{tool.downloads.toLocaleString()}</span>
|
||||
</div>
|
||||
<span className="text-xs">{tool.language}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" className="flex-1" asChild>
|
||||
<Link href={`/marketplace/developers/${tool.id}`}>
|
||||
View Details
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="phoenix" asChild>
|
||||
<Link href={`/marketplace/developers/${tool.id}/install`}>
|
||||
Install
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Publish Your Tool</h2>
|
||||
<p className="mb-6 text-gray-400">
|
||||
Share your tools and libraries with the developer community
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/developers/marketplace/publish">Publish Tool</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
156
src/app/marketplace/page.tsx
Normal file
156
src/app/marketplace/page.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { ProductCard } from '@/components/marketplace/ProductCard'
|
||||
import { Search, Filter } from 'lucide-react'
|
||||
|
||||
const PRODUCT_CATEGORIES = [
|
||||
{ value: 'COMPUTE', label: 'Compute' },
|
||||
{ value: 'NETWORK_INFRA', label: 'Network & Infrastructure' },
|
||||
{ value: 'BLOCKCHAIN_STACK', label: 'Blockchain Stacks' },
|
||||
{ value: 'BLOCKCHAIN_TOOLS', label: 'Blockchain Tools' },
|
||||
{ value: 'FINANCIAL_MESSAGING', label: 'Financial Messaging' },
|
||||
{ value: 'INTERNET_REGISTRY', label: 'Internet Registry' },
|
||||
{ value: 'AI_LLM_AGENT', label: 'AI/LLM Agent' },
|
||||
]
|
||||
|
||||
async function fetchProducts(filter?: any) {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (filter?.category) queryParams.set('category', filter.category)
|
||||
if (filter?.search) queryParams.set('search', filter.search)
|
||||
if (filter?.featured !== undefined) queryParams.set('featured', String(filter.featured))
|
||||
|
||||
const response = await fetch(`/api/graphql?query=${encodeURIComponent(`
|
||||
query GetProducts($filter: ProductFilter) {
|
||||
products(filter: $filter) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
category
|
||||
shortDescription
|
||||
featured
|
||||
iconUrl
|
||||
publisher {
|
||||
displayName
|
||||
verified
|
||||
}
|
||||
averageRating
|
||||
reviewCount
|
||||
}
|
||||
}
|
||||
`)}&variables=${encodeURIComponent(JSON.stringify({ filter }))}`)
|
||||
|
||||
const data = await response.json()
|
||||
return data.data?.products || []
|
||||
}
|
||||
|
||||
export default function MarketplacePage() {
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | undefined>()
|
||||
const [showFeatured, setShowFeatured] = useState(false)
|
||||
|
||||
const filter = {
|
||||
...(selectedCategory && { category: selectedCategory }),
|
||||
...(searchQuery && { search: searchQuery }),
|
||||
...(showFeatured && { featured: true }),
|
||||
}
|
||||
|
||||
const { data: products = [], isLoading } = useQuery({
|
||||
queryKey: ['marketplace-products', filter],
|
||||
queryFn: () => fetchProducts(filter),
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-bold mb-2">Phoenix Marketplace</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Discover and deploy cloud resources, blockchain stacks, and developer tools
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Search and Filters */}
|
||||
<div className="mb-8 space-y-4">
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-1 relative">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
|
||||
<Input
|
||||
placeholder="Search products..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-10"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant={showFeatured ? 'default' : 'outline'}
|
||||
onClick={() => setShowFeatured(!showFeatured)}
|
||||
>
|
||||
<Filter className="mr-2 h-4 w-4" />
|
||||
Featured Only
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Category Filters */}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
variant={!selectedCategory ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setSelectedCategory(undefined)}
|
||||
>
|
||||
All Categories
|
||||
</Button>
|
||||
{PRODUCT_CATEGORIES.map((category) => (
|
||||
<Button
|
||||
key={category.value}
|
||||
variant={selectedCategory === category.value ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setSelectedCategory(
|
||||
selectedCategory === category.value ? undefined : category.value
|
||||
)
|
||||
}
|
||||
>
|
||||
{category.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Products Grid */}
|
||||
{isLoading ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{[1, 2, 3, 4, 5, 6].map((i) => (
|
||||
<Card key={i} className="animate-pulse">
|
||||
<CardHeader>
|
||||
<div className="h-4 bg-muted rounded w-3/4 mb-2" />
|
||||
<div className="h-3 bg-muted rounded w-1/2" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-20 bg-muted rounded" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : products.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<p className="text-muted-foreground">No products found. Try adjusting your filters.</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{products.map((product: any) => (
|
||||
<ProductCard key={product.id} product={product} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
112
src/app/marketplace/partners/page.tsx
Normal file
112
src/app/marketplace/partners/page.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Star, Download, ExternalLink } from 'lucide-react'
|
||||
|
||||
export default function PartnerMarketplacePage() {
|
||||
const solutions = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Enterprise Security Suite',
|
||||
partner: 'SecureCorp',
|
||||
description: 'Comprehensive security solution for enterprise deployments',
|
||||
rating: 4.8,
|
||||
downloads: 1250,
|
||||
category: 'Security',
|
||||
logo: '🔒',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Data Analytics Platform',
|
||||
partner: 'DataFlow Inc',
|
||||
description: 'Advanced analytics and reporting for cloud infrastructure',
|
||||
rating: 4.6,
|
||||
downloads: 890,
|
||||
category: 'Analytics',
|
||||
logo: '📊',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'DevOps Automation Tools',
|
||||
partner: 'AutoDev Solutions',
|
||||
description: 'Automated CI/CD pipelines and deployment workflows',
|
||||
rating: 4.9,
|
||||
downloads: 2100,
|
||||
category: 'DevOps',
|
||||
logo: '⚙️',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">Partner Marketplace</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Discover solutions from our certified partners
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{solutions.map((solution) => (
|
||||
<Card key={solution.id} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div className="text-4xl">{solution.logo}</div>
|
||||
<span className="px-2 py-1 text-xs bg-studio-dark text-gray-400 rounded">
|
||||
{solution.category}
|
||||
</span>
|
||||
</div>
|
||||
<CardTitle className="text-white">{solution.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
by {solution.partner}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-300 mb-4">{solution.description}</p>
|
||||
|
||||
<div className="flex items-center gap-4 mb-4 text-sm text-gray-400">
|
||||
<div className="flex items-center gap-1">
|
||||
<Star className="h-4 w-4 text-yellow-400 fill-yellow-400" />
|
||||
<span>{solution.rating}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<Download className="h-4 w-4" />
|
||||
<span>{solution.downloads.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" className="flex-1" asChild>
|
||||
<Link href={`/marketplace/partners/${solution.id}`}>
|
||||
View Details
|
||||
</Link>
|
||||
</Button>
|
||||
<Button variant="phoenix" asChild>
|
||||
<Link href={`/marketplace/partners/${solution.id}/install`}>
|
||||
Install
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 text-center">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Become a Partner</h2>
|
||||
<p className="mb-6 text-gray-400">
|
||||
List your solution in our marketplace and reach thousands of customers
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/partners/register">Register as Partner</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
291
src/app/marketplace/products/[slug]/page.tsx
Normal file
291
src/app/marketplace/products/[slug]/page.tsx
Normal file
@@ -0,0 +1,291 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { DeploymentWizard } from '@/components/marketplace/DeploymentWizard'
|
||||
import { Star, Verified, ArrowLeft, ExternalLink } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
async function fetchProduct(slug: string) {
|
||||
const response = await fetch(`/api/graphql?query=${encodeURIComponent(`
|
||||
query GetProduct($slug: String!) {
|
||||
productBySlug(slug: $slug) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
category
|
||||
description
|
||||
shortDescription
|
||||
featured
|
||||
iconUrl
|
||||
documentationUrl
|
||||
supportUrl
|
||||
metadata
|
||||
tags
|
||||
publisher {
|
||||
id
|
||||
name
|
||||
displayName
|
||||
verified
|
||||
websiteUrl
|
||||
logoUrl
|
||||
}
|
||||
versions {
|
||||
id
|
||||
version
|
||||
isLatest
|
||||
status
|
||||
releasedAt
|
||||
}
|
||||
pricing {
|
||||
id
|
||||
pricingType
|
||||
basePrice
|
||||
currency
|
||||
billingPeriod
|
||||
}
|
||||
averageRating
|
||||
reviewCount
|
||||
}
|
||||
}
|
||||
`)}&variables=${encodeURIComponent(JSON.stringify({ slug }))}`)
|
||||
|
||||
const data = await response.json()
|
||||
return data.data?.productBySlug
|
||||
}
|
||||
|
||||
export default function ProductDetailPage() {
|
||||
const params = useParams()
|
||||
const router = useRouter()
|
||||
const slug = params.slug as string
|
||||
const [showDeployWizard, setShowDeployWizard] = useState(false)
|
||||
|
||||
const { data: product, isLoading } = useQuery({
|
||||
queryKey: ['product', slug],
|
||||
queryFn: () => fetchProduct(slug),
|
||||
})
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<div className="animate-pulse space-y-4">
|
||||
<div className="h-8 bg-muted rounded w-1/3" />
|
||||
<div className="h-4 bg-muted rounded w-1/2" />
|
||||
<div className="h-64 bg-muted rounded" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!product) {
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<p className="text-muted-foreground mb-4">Product not found</p>
|
||||
<Link href="/marketplace">
|
||||
<Button>Back to Marketplace</Button>
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => router.back()}
|
||||
className="mb-6"
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Back
|
||||
</Button>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Main Content */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
{/* Header */}
|
||||
<div>
|
||||
<div className="flex items-start gap-4 mb-4">
|
||||
{product.iconUrl && (
|
||||
<img
|
||||
src={product.iconUrl}
|
||||
alt={product.name}
|
||||
className="w-20 h-20 rounded-lg object-cover"
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<h1 className="text-4xl font-bold mb-2">{product.name}</h1>
|
||||
<div className="flex items-center gap-2 text-muted-foreground mb-2">
|
||||
{product.publisher && (
|
||||
<>
|
||||
<span>by {product.publisher.displayName}</span>
|
||||
{product.publisher.verified && (
|
||||
<Verified className="h-4 w-4 text-blue-500" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Badge variant="secondary">{product.category}</Badge>
|
||||
{product.featured && <Badge>Featured</Badge>}
|
||||
{product.averageRating !== undefined && product.averageRating > 0 && (
|
||||
<div className="flex items-center gap-1">
|
||||
<Star className="h-4 w-4 fill-yellow-400 text-yellow-400" />
|
||||
<span className="text-sm font-medium">
|
||||
{product.averageRating.toFixed(1)}
|
||||
</span>
|
||||
{product.reviewCount !== undefined && product.reviewCount > 0 && (
|
||||
<span className="text-sm text-muted-foreground">
|
||||
({product.reviewCount} reviews)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Description</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-muted-foreground whitespace-pre-wrap">
|
||||
{product.description || product.shortDescription || 'No description available'}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Versions */}
|
||||
{product.versions && product.versions.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Versions</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2">
|
||||
{product.versions.map((version: any) => (
|
||||
<div
|
||||
key={version.id}
|
||||
className="flex items-center justify-between p-2 border rounded"
|
||||
>
|
||||
<div>
|
||||
<span className="font-medium">v{version.version}</span>
|
||||
{version.isLatest && (
|
||||
<Badge variant="outline" className="ml-2">
|
||||
Latest
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{version.releasedAt && (
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{new Date(version.releasedAt).toLocaleDateString()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Tags */}
|
||||
{product.tags && product.tags.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Tags</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{product.tags.map((tag: string) => (
|
||||
<Badge key={tag} variant="outline">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="space-y-6">
|
||||
{/* Pricing */}
|
||||
{product.pricing && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Pricing</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{product.pricing.pricingType === 'FREE' ? (
|
||||
<div className="text-2xl font-bold">Free</div>
|
||||
) : (
|
||||
<div>
|
||||
{product.pricing.basePrice !== null && (
|
||||
<div className="text-2xl font-bold">
|
||||
${product.pricing.basePrice}
|
||||
{product.pricing.billingPeriod && (
|
||||
<span className="text-sm font-normal text-muted-foreground">
|
||||
/{product.pricing.billingPeriod.toLowerCase()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-sm text-muted-foreground mt-1">
|
||||
{product.pricing.pricingType}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Actions */}
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<Button
|
||||
className="w-full mb-2"
|
||||
onClick={() => setShowDeployWizard(true)}
|
||||
>
|
||||
Deploy Now
|
||||
</Button>
|
||||
{product.documentationUrl && (
|
||||
<Link href={product.documentationUrl} target="_blank">
|
||||
<Button variant="outline" className="w-full mb-2">
|
||||
<ExternalLink className="mr-2 h-4 w-4" />
|
||||
Documentation
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
{product.supportUrl && (
|
||||
<Link href={product.supportUrl} target="_blank">
|
||||
<Button variant="outline" className="w-full">
|
||||
Get Support
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Deployment Wizard Modal */}
|
||||
{showDeployWizard && (
|
||||
<DeploymentWizard
|
||||
product={product}
|
||||
onClose={() => setShowDeployWizard(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero Section */}
|
||||
<section className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
<span className="bg-gradient-to-r from-phoenix-fire to-sankofa-gold bg-clip-text text-transparent">
|
||||
Sankofa's
|
||||
</span>{' '}
|
||||
Phoenix{' '}
|
||||
<span className="bg-gradient-to-r from-phoenix-fire to-sankofa-gold bg-clip-text text-transparent">
|
||||
Sankofa
|
||||
Nexus
|
||||
</span>{' '}
|
||||
Cloud
|
||||
</h1>
|
||||
@@ -104,7 +109,8 @@ export default function Home() {
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
158
src/app/partners/page.tsx
Normal file
158
src/app/partners/page.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Handshake, TrendingUp, Users, Award, Zap, BookOpen } from 'lucide-react'
|
||||
|
||||
export default function PartnersPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Partner Program
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Build, sell, and grow with Sankofa's Phoenix Nexus Cloud
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/partners">Join as Partner</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/partners/benefits">View Benefits</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Partner Benefits */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Partner Benefits
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<TrendingUp className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Revenue Opportunities</CardTitle>
|
||||
<CardDescription>
|
||||
Competitive margins and co-sell opportunities
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Attractive partner margins</li>
|
||||
<li>• Co-sell deal registration</li>
|
||||
<li>• Recurring revenue streams</li>
|
||||
<li>• Marketing development funds</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Zap className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Technical Enablement</CardTitle>
|
||||
<CardDescription>
|
||||
Comprehensive training and support resources
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Technical onboarding programs</li>
|
||||
<li>• Solution architecture support</li>
|
||||
<li>• Dedicated partner engineering</li>
|
||||
<li>• Test environments and sandboxes</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Users className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Go-to-Market Support</CardTitle>
|
||||
<CardDescription>
|
||||
Marketing resources and co-marketing opportunities
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Co-marketing campaigns</li>
|
||||
<li>• Partner portal access</li>
|
||||
<li>• Sales enablement materials</li>
|
||||
<li>• Joint customer events</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Partner Types */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Partner Types
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<Handshake className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Solution Partners</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Build and deliver solutions on Phoenix Nexus Cloud. Integrate your
|
||||
products and services with our platform.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Solution marketplace listing</li>
|
||||
<li>• Technical integration support</li>
|
||||
<li>• Joint go-to-market</li>
|
||||
<li>• Solution certification</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Award className="mb-4 h-8 w-8 text-sankofa-gold" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Reseller Partners</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Sell Phoenix Nexus Cloud to your customers. Leverage our infrastructure
|
||||
to deliver value to your client base.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Reseller discounts</li>
|
||||
<li>• Deal registration</li>
|
||||
<li>• Sales training</li>
|
||||
<li>• Customer support tools</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Partner With Us?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Join our partner program and grow your business
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/partners">Access Partner Portal</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/support">Contact Partner Team</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
161
src/app/portal/admin/page.tsx
Normal file
161
src/app/portal/admin/page.tsx
Normal file
@@ -0,0 +1,161 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Users, Building2, CreditCard, Settings, Shield, BarChart3 } from 'lucide-react'
|
||||
|
||||
export default function AdminPortalPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-bold text-white">Tenant Administration</h1>
|
||||
<p className="mt-2 text-gray-400">
|
||||
Manage your organization, users, permissions, and billing
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-phoenix-fire/20 p-3">
|
||||
<Building2 className="h-6 w-6 text-phoenix-fire" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Organization</CardTitle>
|
||||
<CardDescription>Manage organization settings</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Configure organization details, domains, and branding
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/organization">Manage Organization</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-sankofa-gold/20 p-3">
|
||||
<Users className="h-6 w-6 text-sankofa-gold" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Users & Roles</CardTitle>
|
||||
<CardDescription>Manage team members</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Invite users, assign roles, and manage permissions
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/users">Manage Users</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-neon-cyan/20 p-3">
|
||||
<Shield className="h-6 w-6 text-neon-cyan" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Permissions</CardTitle>
|
||||
<CardDescription>Configure access controls</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Set up role-based access control and permissions
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/permissions">Manage Permissions</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-phoenix-fire/20 p-3">
|
||||
<CreditCard className="h-6 w-6 text-phoenix-fire" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Billing</CardTitle>
|
||||
<CardDescription>Manage subscriptions</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
View invoices, manage payment methods, and billing settings
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/billing">Manage Billing</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-sankofa-gold/20 p-3">
|
||||
<BarChart3 className="h-6 w-6 text-sankofa-gold" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Usage & Analytics</CardTitle>
|
||||
<CardDescription>Monitor resource usage</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Track usage, costs, and performance metrics
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/analytics">View Analytics</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-studio-medium hover:border-phoenix-fire/50 transition-colors">
|
||||
<CardHeader>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="rounded-lg bg-neon-cyan/20 p-3">
|
||||
<Settings className="h-6 w-6 text-neon-cyan" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>Settings</CardTitle>
|
||||
<CardDescription>Configure preferences</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-sm text-gray-400">
|
||||
Manage security, notifications, and integrations
|
||||
</p>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href="/portal/admin/settings">Manage Settings</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
58
src/app/portal/callback/page.tsx
Normal file
58
src/app/portal/callback/page.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { handleSSOCallback, getPortalForRole } from '@/lib/auth/sso'
|
||||
|
||||
export default function SSOCallbackPage() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
useEffect(() => {
|
||||
const code = searchParams?.get('code')
|
||||
const state = searchParams?.get('state')
|
||||
|
||||
if (code && state) {
|
||||
const keycloakUrl = process.env.NEXT_PUBLIC_KEYCLOAK_URL || 'https://keycloak.sankofa.nexus'
|
||||
const realm = process.env.NEXT_PUBLIC_KEYCLOAK_REALM || 'sankofa'
|
||||
const clientId = process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID || 'phoenix-portal'
|
||||
const redirectUri = `${window.location.origin}/portal/callback`
|
||||
|
||||
handleSSOCallback(code, state, {
|
||||
keycloakUrl,
|
||||
realm,
|
||||
clientId,
|
||||
redirectUri,
|
||||
})
|
||||
.then(({ token, user, role }) => {
|
||||
// Store token
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem('auth_token', token)
|
||||
localStorage.setItem('phoenix_token', token)
|
||||
localStorage.setItem('phoenix_user', JSON.stringify(user))
|
||||
}
|
||||
|
||||
// Route to appropriate portal
|
||||
const portal = getPortalForRole(role)
|
||||
router.push(portal)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('SSO callback error:', error)
|
||||
router.push('/portal/signin?error=sso_failed')
|
||||
})
|
||||
} else {
|
||||
// No code/state, redirect to sign in
|
||||
router.push('/portal/signin')
|
||||
}
|
||||
}, [searchParams, router])
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-studio-black">
|
||||
<div className="text-center">
|
||||
<div className="mb-4 inline-block h-8 w-8 animate-spin rounded-full border-4 border-phoenix-fire border-t-transparent" />
|
||||
<p className="text-gray-400">Completing sign in...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
394
src/app/portal/developers/environments/page.tsx
Normal file
394
src/app/portal/developers/environments/page.tsx
Normal file
@@ -0,0 +1,394 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useQuery, useMutation } from '@apollo/client'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Terminal, Plus, Trash2, Play, Square, RefreshCw, Loader2 } from 'lucide-react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import {
|
||||
GET_TEST_ENVIRONMENTS,
|
||||
CREATE_TEST_ENVIRONMENT,
|
||||
START_TEST_ENVIRONMENT,
|
||||
STOP_TEST_ENVIRONMENT,
|
||||
DELETE_TEST_ENVIRONMENT,
|
||||
} from '@/lib/graphql/queries/test-environments'
|
||||
|
||||
interface Environment {
|
||||
id: string
|
||||
name: string
|
||||
status: 'RUNNING' | 'STOPPED' | 'PROVISIONING' | 'ERROR' | 'DELETING'
|
||||
region: string
|
||||
resources: {
|
||||
vms: number
|
||||
storage: string
|
||||
network: string
|
||||
}
|
||||
created: string
|
||||
expires?: string
|
||||
}
|
||||
|
||||
export default function EnvironmentsPage() {
|
||||
const [showCreate, setShowCreate] = useState(false)
|
||||
const [newEnvName, setNewEnvName] = useState('')
|
||||
const [newEnvRegion, setNewEnvRegion] = useState('us-east-1')
|
||||
|
||||
// Fetch test environments
|
||||
const { data, loading, error, refetch } = useQuery(GET_TEST_ENVIRONMENTS, {
|
||||
onCompleted: (data) => {
|
||||
// Data is handled in the component
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error fetching test environments:', error)
|
||||
},
|
||||
})
|
||||
|
||||
// Create environment mutation
|
||||
const [createEnvironment, { loading: creating }] = useMutation(CREATE_TEST_ENVIRONMENT, {
|
||||
onCompleted: () => {
|
||||
setNewEnvName('')
|
||||
setNewEnvRegion('us-east-1')
|
||||
setShowCreate(false)
|
||||
refetch()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error creating environment:', error)
|
||||
alert('Failed to create environment: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
// Start environment mutation
|
||||
const [startEnvironment, { loading: starting }] = useMutation(START_TEST_ENVIRONMENT, {
|
||||
onCompleted: () => {
|
||||
refetch()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error starting environment:', error)
|
||||
alert('Failed to start environment: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
// Stop environment mutation
|
||||
const [stopEnvironment, { loading: stopping }] = useMutation(STOP_TEST_ENVIRONMENT, {
|
||||
onCompleted: () => {
|
||||
refetch()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error stopping environment:', error)
|
||||
alert('Failed to stop environment: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
// Delete environment mutation
|
||||
const [deleteEnvironment, { loading: deleting }] = useMutation(DELETE_TEST_ENVIRONMENT, {
|
||||
onCompleted: () => {
|
||||
refetch()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error deleting environment:', error)
|
||||
alert('Failed to delete environment: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
const environments: Environment[] = data?.testEnvironments?.map((env: any) => ({
|
||||
id: env.id,
|
||||
name: env.name,
|
||||
status: env.status,
|
||||
region: env.region,
|
||||
resources: env.resources,
|
||||
created: new Date(env.createdAt).toLocaleDateString(),
|
||||
expires: env.expiresAt ? new Date(env.expiresAt).toLocaleDateString() : undefined,
|
||||
})) || []
|
||||
|
||||
const handleCreate = () => {
|
||||
if (!newEnvName.trim()) return
|
||||
|
||||
createEnvironment({
|
||||
variables: {
|
||||
input: {
|
||||
name: newEnvName,
|
||||
region: newEnvRegion,
|
||||
resources: {
|
||||
vms: 1,
|
||||
storage: '20 GB',
|
||||
network: '10.0.0.0/16',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = (id: string) => {
|
||||
startEnvironment({ variables: { id } })
|
||||
}
|
||||
|
||||
const handleStop = (id: string) => {
|
||||
stopEnvironment({ variables: { id } })
|
||||
}
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
if (confirm('Are you sure you want to delete this environment? All data will be lost.')) {
|
||||
deleteEnvironment({ variables: { id } })
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'RUNNING':
|
||||
return 'bg-green-500'
|
||||
case 'STOPPED':
|
||||
return 'bg-gray-500'
|
||||
case 'PROVISIONING':
|
||||
return 'bg-yellow-500'
|
||||
case 'ERROR':
|
||||
return 'bg-red-500'
|
||||
default:
|
||||
return 'bg-gray-500'
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-phoenix-fire" />
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold text-white">Test Environments</h1>
|
||||
<p className="mt-2 text-gray-400">
|
||||
Provision and manage sandbox environments for testing
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="phoenix"
|
||||
onClick={() => setShowCreate(!showCreate)}
|
||||
disabled={creating}
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Create Environment
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<Card className="mb-8 border-red-500/50">
|
||||
<CardContent className="py-4">
|
||||
<p className="text-red-500">
|
||||
Error loading environments: {error.message}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{showCreate && (
|
||||
<Card className="mb-8 border-phoenix-fire/50">
|
||||
<CardHeader>
|
||||
<CardTitle>Create New Test Environment</CardTitle>
|
||||
<CardDescription>
|
||||
Provision a new sandbox environment for testing
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Environment Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={newEnvName}
|
||||
onChange={(e) => setNewEnvName(e.target.value)}
|
||||
placeholder="e.g., Development Sandbox"
|
||||
className="w-full rounded bg-studio-dark px-4 py-2 text-white border border-studio-medium"
|
||||
disabled={creating}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Region
|
||||
</label>
|
||||
<select
|
||||
value={newEnvRegion}
|
||||
onChange={(e) => setNewEnvRegion(e.target.value)}
|
||||
className="w-full rounded bg-studio-dark px-4 py-2 text-white border border-studio-medium"
|
||||
disabled={creating}
|
||||
>
|
||||
<option value="us-east-1">US East (N. Virginia)</option>
|
||||
<option value="us-west-2">US West (Oregon)</option>
|
||||
<option value="eu-west-1">EU (Ireland)</option>
|
||||
<option value="ap-southeast-1">Asia Pacific (Singapore)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={handleCreate}
|
||||
disabled={!newEnvName.trim() || creating}
|
||||
>
|
||||
{creating ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Creating...
|
||||
</>
|
||||
) : (
|
||||
'Create Environment'
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowCreate(false)}
|
||||
disabled={creating}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{environments.length === 0 && !loading ? (
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<Terminal className="mx-auto mb-4 h-12 w-12 text-gray-400" />
|
||||
<h3 className="mb-2 text-lg font-semibold text-white">No Environments</h3>
|
||||
<p className="mb-4 text-gray-400">
|
||||
Create a test environment to start developing
|
||||
</p>
|
||||
<Button variant="phoenix" onClick={() => setShowCreate(true)}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Create Environment
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="grid gap-6 md:grid-cols-2">
|
||||
{environments.map((env) => (
|
||||
<Card key={env.id}>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5 text-sankofa-gold" />
|
||||
{env.name}
|
||||
</CardTitle>
|
||||
<CardDescription className="mt-1">
|
||||
{env.region} • Created {env.created}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`h-3 w-3 rounded-full ${getStatusColor(env.status)}`} />
|
||||
<Badge variant="outline">{env.status}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h4 className="mb-2 text-sm font-semibold text-gray-400">Resources</h4>
|
||||
<div className="grid grid-cols-3 gap-2 text-sm">
|
||||
<div>
|
||||
<div className="text-gray-500">VMs</div>
|
||||
<div className="font-semibold text-white">{env.resources.vms}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-gray-500">Storage</div>
|
||||
<div className="font-semibold text-white">{env.resources.storage}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-gray-500">Network</div>
|
||||
<div className="font-semibold text-white">{env.resources.network}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{env.expires && (
|
||||
<div className="rounded bg-yellow-500/10 px-3 py-2 text-sm text-yellow-500">
|
||||
Expires: {env.expires}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2">
|
||||
{env.status === 'STOPPED' ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleStart(env.id)}
|
||||
disabled={starting}
|
||||
>
|
||||
{starting ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Start
|
||||
</Button>
|
||||
) : env.status === 'RUNNING' ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleStop(env.id)}
|
||||
disabled={stopping}
|
||||
>
|
||||
{stopping ? (
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Square className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Stop
|
||||
</Button>
|
||||
) : env.status === 'PROVISIONING' ? (
|
||||
<Button variant="outline" size="sm" disabled>
|
||||
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
|
||||
Provisioning...
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleDelete(env.id)}
|
||||
disabled={deleting || env.status === 'PROVISIONING'}
|
||||
>
|
||||
{deleting ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Trash2 className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Card className="mt-8 border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle>About Test Environments</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Environments are automatically cleaned up after 30 days</li>
|
||||
<li>• Free tier includes 2 environments with basic resources</li>
|
||||
<li>• All data is isolated and secure</li>
|
||||
<li>• Environments can be started/stopped on demand</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
359
src/app/portal/developers/keys/page.tsx
Normal file
359
src/app/portal/developers/keys/page.tsx
Normal file
@@ -0,0 +1,359 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useQuery, useMutation } from '@apollo/client'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Key, Plus, Trash2, Eye, EyeOff, Copy, CheckCircle, Loader2 } from 'lucide-react'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import {
|
||||
GET_API_KEYS,
|
||||
CREATE_API_KEY,
|
||||
REVOKE_API_KEY,
|
||||
} from '@/lib/graphql/queries/api-keys'
|
||||
|
||||
interface ApiKey {
|
||||
id: string
|
||||
name: string
|
||||
keyPrefix: string
|
||||
created: string
|
||||
lastUsed: string
|
||||
permissions: string[]
|
||||
masked: boolean
|
||||
fullKey?: string // Only available immediately after creation
|
||||
}
|
||||
|
||||
export default function ApiKeysPage() {
|
||||
const [keys, setKeys] = useState<ApiKey[]>([])
|
||||
const [showCreate, setShowCreate] = useState(false)
|
||||
const [newKeyName, setNewKeyName] = useState('')
|
||||
const [copiedId, setCopiedId] = useState<string | null>(null)
|
||||
const [newlyCreatedKey, setNewlyCreatedKey] = useState<string | null>(null)
|
||||
|
||||
// Fetch API keys
|
||||
const { data, loading, error, refetch } = useQuery(GET_API_KEYS, {
|
||||
onCompleted: (data) => {
|
||||
if (data?.apiKeys) {
|
||||
setKeys(
|
||||
data.apiKeys.map((key: any) => ({
|
||||
id: key.id,
|
||||
name: key.name,
|
||||
keyPrefix: key.keyPrefix,
|
||||
key: `${key.keyPrefix}...`,
|
||||
created: new Date(key.createdAt).toLocaleDateString(),
|
||||
lastUsed: key.lastUsedAt
|
||||
? new Date(key.lastUsedAt).toLocaleDateString()
|
||||
: 'Never',
|
||||
permissions: key.permissions || [],
|
||||
masked: true,
|
||||
}))
|
||||
)
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error fetching API keys:', error)
|
||||
},
|
||||
})
|
||||
|
||||
// Create API key mutation
|
||||
const [createApiKey, { loading: creating }] = useMutation(CREATE_API_KEY, {
|
||||
onCompleted: (data) => {
|
||||
if (data?.createApiKey) {
|
||||
const newKey = data.createApiKey
|
||||
setNewlyCreatedKey(newKey.key)
|
||||
setKeys([
|
||||
{
|
||||
id: newKey.id,
|
||||
name: newKey.name,
|
||||
keyPrefix: newKey.key.substring(0, 12),
|
||||
key: newKey.key,
|
||||
created: new Date(newKey.createdAt).toLocaleDateString(),
|
||||
lastUsed: 'Never',
|
||||
permissions: ['read', 'write'],
|
||||
masked: false,
|
||||
fullKey: newKey.key,
|
||||
},
|
||||
...keys,
|
||||
])
|
||||
setNewKeyName('')
|
||||
setShowCreate(false)
|
||||
// Refetch to get updated list
|
||||
refetch()
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error creating API key:', error)
|
||||
alert('Failed to create API key: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
// Revoke API key mutation
|
||||
const [revokeApiKey, { loading: revoking }] = useMutation(REVOKE_API_KEY, {
|
||||
onCompleted: () => {
|
||||
refetch()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Error revoking API key:', error)
|
||||
alert('Failed to revoke API key: ' + error.message)
|
||||
},
|
||||
})
|
||||
|
||||
const handleCreateKey = () => {
|
||||
if (!newKeyName.trim()) return
|
||||
|
||||
createApiKey({
|
||||
variables: {
|
||||
input: {
|
||||
name: newKeyName,
|
||||
permissions: ['read', 'write'],
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteKey = (id: string) => {
|
||||
if (confirm('Are you sure you want to revoke this API key? It will no longer work.')) {
|
||||
revokeApiKey({
|
||||
variables: { id },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMask = (id: string) => {
|
||||
setKeys(keys.map((k) => (k.id === id ? { ...k, masked: !k.masked } : k)))
|
||||
}
|
||||
|
||||
const copyKey = (key: string, id: string) => {
|
||||
navigator.clipboard.writeText(key)
|
||||
setCopiedId(id)
|
||||
setTimeout(() => setCopiedId(null), 2000)
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-phoenix-fire" />
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
<div className="container mx-auto py-12 px-4">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold text-white">API Keys</h1>
|
||||
<p className="mt-2 text-gray-400">
|
||||
Manage API keys for your applications
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="phoenix"
|
||||
onClick={() => setShowCreate(!showCreate)}
|
||||
disabled={creating}
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Create API Key
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<Card className="mb-8 border-red-500/50">
|
||||
<CardContent className="py-4">
|
||||
<p className="text-red-500">
|
||||
Error loading API keys: {error.message}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{newlyCreatedKey && (
|
||||
<Card className="mb-8 border-green-500/50 bg-green-500/10">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-green-500">API Key Created!</CardTitle>
|
||||
<CardDescription>
|
||||
Copy this key now. You won't be able to see it again.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white break-all">
|
||||
{newlyCreatedKey}
|
||||
</code>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(newlyCreatedKey)
|
||||
setNewlyCreatedKey(null)
|
||||
}}
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{showCreate && (
|
||||
<Card className="mb-8 border-phoenix-fire/50">
|
||||
<CardHeader>
|
||||
<CardTitle>Create New API Key</CardTitle>
|
||||
<CardDescription>
|
||||
Give your API key a descriptive name to identify its purpose
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="key-name">Key Name</Label>
|
||||
<Input
|
||||
id="key-name"
|
||||
value={newKeyName}
|
||||
onChange={(e) => setNewKeyName(e.target.value)}
|
||||
placeholder="e.g., Production App, Test Environment"
|
||||
className="mt-2"
|
||||
disabled={creating}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={handleCreateKey}
|
||||
disabled={!newKeyName.trim() || creating}
|
||||
>
|
||||
{creating ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Creating...
|
||||
</>
|
||||
) : (
|
||||
'Create Key'
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowCreate(false)}
|
||||
disabled={creating}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{keys.length === 0 && !loading ? (
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<Key className="mx-auto mb-4 h-12 w-12 text-gray-400" />
|
||||
<h3 className="mb-2 text-lg font-semibold text-white">No API Keys</h3>
|
||||
<p className="mb-4 text-gray-400">
|
||||
Create your first API key to start using the Phoenix Nexus API
|
||||
</p>
|
||||
<Button variant="phoenix" onClick={() => setShowCreate(true)}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Create API Key
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{keys.map((key) => (
|
||||
<Card key={key.id}>
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Key className="h-5 w-5 text-phoenix-fire" />
|
||||
{key.name}
|
||||
</CardTitle>
|
||||
<CardDescription className="mt-1">
|
||||
Created {key.created} • Last used {key.lastUsed}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleDeleteKey(key.id)}
|
||||
disabled={revoking}
|
||||
>
|
||||
{revoking ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Trash2 className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 rounded bg-studio-dark px-4 py-2 font-mono text-sm text-white">
|
||||
{key.masked && !key.fullKey ? key.key : key.fullKey || key.key}
|
||||
</code>
|
||||
{key.fullKey && (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => toggleMask(key.id)}
|
||||
>
|
||||
{key.masked ? <Eye className="h-4 w-4" /> : <EyeOff className="h-4 w-4" />}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => copyKey(key.fullKey || key.key, key.id)}
|
||||
>
|
||||
{copiedId === key.id ? (
|
||||
<CheckCircle className="h-4 w-4 text-green-500" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{key.permissions.map((perm) => (
|
||||
<span
|
||||
key={perm}
|
||||
className="rounded-full bg-phoenix-fire/20 px-3 py-1 text-xs text-phoenix-fire"
|
||||
>
|
||||
{perm}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Card className="mt-8 border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle>Security Best Practices</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Never commit API keys to version control</li>
|
||||
<li>• Use environment variables to store keys</li>
|
||||
<li>• Rotate keys regularly</li>
|
||||
<li>• Delete unused keys immediately</li>
|
||||
<li>• Use different keys for different environments</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
183
src/app/portal/developers/page.tsx
Normal file
183
src/app/portal/developers/page.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Key, Terminal, FileText, Activity, Code, Settings } from 'lucide-react'
|
||||
|
||||
export default function DeveloperPortalPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Developer Portal
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Manage API keys, test environments, and developer resources
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/developers/keys">Get API Keys</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/developers/docs">View Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Developer Tools */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Developer Tools
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers/keys">
|
||||
<CardHeader>
|
||||
<Key className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>API Keys</CardTitle>
|
||||
<CardDescription>
|
||||
Create and manage API keys for your applications
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Generate keys, set permissions, and monitor usage
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers/environments">
|
||||
<CardHeader>
|
||||
<Terminal className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Test Environments</CardTitle>
|
||||
<CardDescription>
|
||||
Provision and manage sandbox environments
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Instant provisioning with automatic cleanup
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers/logs">
|
||||
<CardHeader>
|
||||
<FileText className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>API Logs</CardTitle>
|
||||
<CardDescription>
|
||||
View and analyze API request logs
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Real-time log streaming and search
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers/analytics">
|
||||
<CardHeader>
|
||||
<Activity className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Usage Analytics</CardTitle>
|
||||
<CardDescription>
|
||||
Monitor API usage and performance
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Track requests, errors, and quotas
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs">
|
||||
<CardHeader>
|
||||
<Code className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Documentation</CardTitle>
|
||||
<CardDescription>
|
||||
API references and integration guides
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Comprehensive guides and examples
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/developers/settings">
|
||||
<CardHeader>
|
||||
<Settings className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Settings</CardTitle>
|
||||
<CardDescription>
|
||||
Configure developer account settings
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Manage preferences and notifications
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-8 text-3xl font-bold text-white">Quick Actions</h2>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Get Started</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-gray-300">
|
||||
New to Phoenix Nexus? Create your first API key and start building.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/developers/docs/quickstart">Quick Start Guide →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Need Help?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Check the documentation or contact our developer support team.
|
||||
</p>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/support">Contact Support →</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
139
src/app/portal/partners/page.tsx
Normal file
139
src/app/portal/partners/page.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Handshake, TrendingUp, FileText, Users, Award, Settings } from 'lucide-react'
|
||||
|
||||
export default function PartnerPortalPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Partner Portal
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Manage deals, solutions, and partner resources
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Partner Tools */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Partner Resources
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/deals">
|
||||
<CardHeader>
|
||||
<TrendingUp className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Deal Registration</CardTitle>
|
||||
<CardDescription>
|
||||
Register and track co-sell opportunities
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Submit deals, track status, and manage opportunities
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/solutions">
|
||||
<CardHeader>
|
||||
<FileText className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Solution Marketplace</CardTitle>
|
||||
<CardDescription>
|
||||
List and manage your solutions
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Submit solutions for marketplace listing
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/onboarding">
|
||||
<CardHeader>
|
||||
<Users className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Technical Onboarding</CardTitle>
|
||||
<CardDescription>
|
||||
Access onboarding resources and training
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Technical enablement and certification
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/resources">
|
||||
<CardHeader>
|
||||
<Award className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Marketing Resources</CardTitle>
|
||||
<CardDescription>
|
||||
Co-marketing materials and assets
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Logos, templates, and campaign materials
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/analytics">
|
||||
<CardHeader>
|
||||
<TrendingUp className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Partner Analytics</CardTitle>
|
||||
<CardDescription>
|
||||
Track performance and revenue
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
View deal pipeline and performance metrics
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/portal/partners/settings">
|
||||
<CardHeader>
|
||||
<Settings className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Partner Settings</CardTitle>
|
||||
<CardDescription>
|
||||
Manage partner account and preferences
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-gray-400">
|
||||
Update profile and notification preferences
|
||||
</p>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
242
src/app/portal/signin/page.tsx
Normal file
242
src/app/portal/signin/page.tsx
Normal file
@@ -0,0 +1,242 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Key, ArrowRight, Loader2 } from 'lucide-react'
|
||||
import { initiateSSO, getPortalForRole, isAuthenticated } from '@/lib/auth/sso'
|
||||
|
||||
export default function SignInPage() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const [ssoLoading, setSsoLoading] = useState(false)
|
||||
|
||||
// Check if already authenticated
|
||||
useEffect(() => {
|
||||
if (isAuthenticated()) {
|
||||
router.push('/portal')
|
||||
}
|
||||
}, [router])
|
||||
|
||||
// Handle Keycloak SSO callback
|
||||
useEffect(() => {
|
||||
const code = searchParams?.get('code')
|
||||
const state = searchParams?.get('state')
|
||||
|
||||
if (code && state) {
|
||||
// Handle SSO callback - would integrate with actual Keycloak
|
||||
// For now, redirect to portal
|
||||
router.push('/portal')
|
||||
}
|
||||
}, [searchParams, router])
|
||||
|
||||
const handleSignIn = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
setError('')
|
||||
|
||||
try {
|
||||
// TODO: Integrate with actual authentication API
|
||||
// For now, use GraphQL login mutation
|
||||
const response = await fetch(
|
||||
process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || 'http://localhost:4000/graphql',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query: `
|
||||
mutation Login($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
token
|
||||
user {
|
||||
id
|
||||
email
|
||||
name
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { email, password },
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (result.errors) {
|
||||
setError(result.errors[0].message || 'Invalid email or password')
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (result.data?.login) {
|
||||
// Store token
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem('auth_token', result.data.login.token)
|
||||
localStorage.setItem('phoenix_token', result.data.login.token)
|
||||
}
|
||||
|
||||
// Determine portal based on role
|
||||
const role = result.data.login.user.role.toLowerCase()
|
||||
const portal = getPortalForRole(role)
|
||||
router.push(portal)
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Failed to sign in. Please try again.')
|
||||
console.error('Sign in error:', err)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeycloakSSO = async () => {
|
||||
setSsoLoading(true)
|
||||
try {
|
||||
const keycloakUrl = process.env.NEXT_PUBLIC_KEYCLOAK_URL || 'https://keycloak.sankofa.nexus'
|
||||
const realm = process.env.NEXT_PUBLIC_KEYCLOAK_REALM || 'sankofa'
|
||||
const clientId = process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID || 'phoenix-portal'
|
||||
const redirectUri = `${window.location.origin}/portal/signin`
|
||||
|
||||
const ssoUrl = await initiateSSO({
|
||||
keycloakUrl,
|
||||
realm,
|
||||
clientId,
|
||||
redirectUri,
|
||||
})
|
||||
|
||||
window.location.href = ssoUrl
|
||||
} catch (err) {
|
||||
setError('Failed to initiate SSO. Please try again.')
|
||||
console.error('SSO error:', err)
|
||||
setSsoLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const isKeycloakConfigured =
|
||||
typeof window !== 'undefined' &&
|
||||
(process.env.NEXT_PUBLIC_KEYCLOAK_URL || process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black flex items-center justify-center px-4">
|
||||
<Card className="w-full max-w-md border-studio-medium">
|
||||
<CardHeader className="text-center">
|
||||
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-phoenix-fire/20">
|
||||
<Key className="h-6 w-6 text-phoenix-fire" />
|
||||
</div>
|
||||
<CardTitle className="text-2xl">Sign In</CardTitle>
|
||||
<CardDescription>
|
||||
Access your Phoenix Nexus portals
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSignIn} className="space-y-4">
|
||||
{error && (
|
||||
<div className="rounded bg-red-500/10 px-4 py-3 text-sm text-red-500">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="you@example.com"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Link
|
||||
href="/portal/forgot-password"
|
||||
className="text-sm text-phoenix-fire hover:underline"
|
||||
>
|
||||
Forgot password?
|
||||
</Link>
|
||||
</div>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="phoenix"
|
||||
className="w-full"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Signing in...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Sign In
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<div className="text-center text-sm text-gray-400">
|
||||
Don't have an account?{' '}
|
||||
<Link href="/portal/get-started" className="text-phoenix-fire hover:underline">
|
||||
Get started
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{isKeycloakConfigured && (
|
||||
<div className="mt-6 border-t border-studio-medium pt-6">
|
||||
<p className="mb-4 text-center text-sm text-gray-400">
|
||||
Or continue with
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={handleKeycloakSSO}
|
||||
disabled={ssoLoading || loading}
|
||||
>
|
||||
{ssoLoading ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Connecting...
|
||||
</>
|
||||
) : (
|
||||
'Keycloak SSO'
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
254
src/app/products/[slug]/page.tsx
Normal file
254
src/app/products/[slug]/page.tsx
Normal file
@@ -0,0 +1,254 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { ArrowLeft, Check } from 'lucide-react'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
// Product catalog with details
|
||||
const products = {
|
||||
'phoenixcore-compute': {
|
||||
name: 'PhoenixCore Compute',
|
||||
category: 'Compute',
|
||||
description: 'Core compute engine powered by Phoenix fire',
|
||||
longDescription: 'PhoenixCore Compute delivers high-performance virtual machines and container orchestration with enterprise-grade reliability. Built on our global edge infrastructure, it provides low-latency compute resources across 325+ regions worldwide.',
|
||||
features: [
|
||||
'High-performance CPUs (AMD EPYC / Intel Xeon)',
|
||||
'NVMe storage for ultra-fast I/O',
|
||||
'Global edge deployment',
|
||||
'Auto-scaling capabilities',
|
||||
'99.99% uptime SLA',
|
||||
'Blockchain-verified resource tracking',
|
||||
],
|
||||
pricing: {
|
||||
base: 0.05, // per vCPU hour
|
||||
memory: 0.01, // per GB hour
|
||||
storage: 0.001, // per GB hour
|
||||
currency: 'USD',
|
||||
},
|
||||
tiers: [
|
||||
{ name: 'Starter', vcpu: 2, memory: 4, price: 50 },
|
||||
{ name: 'Professional', vcpu: 8, memory: 16, price: 200 },
|
||||
{ name: 'Enterprise', vcpu: 32, memory: 64, price: 800 },
|
||||
],
|
||||
},
|
||||
'sankofaedge-nodes': {
|
||||
name: 'SankofaEdge Nodes',
|
||||
category: 'Compute',
|
||||
description: 'Edge nodes that remember and return data',
|
||||
longDescription: 'SankofaEdge Nodes provide low-latency compute at the network edge, bringing your applications closer to users worldwide. With 250+ edge locations, reduce latency and improve user experience.',
|
||||
features: [
|
||||
'250+ global edge locations',
|
||||
'Sub-10ms latency',
|
||||
'CDN integration',
|
||||
'Edge caching',
|
||||
'Regional data residency',
|
||||
],
|
||||
pricing: {
|
||||
base: 0.03,
|
||||
currency: 'USD',
|
||||
},
|
||||
},
|
||||
'okravault-storage': {
|
||||
name: 'OkraVault Storage',
|
||||
category: 'Storage',
|
||||
description: 'Storage for the soul of your data',
|
||||
longDescription: 'OkraVault provides secure, scalable object and block storage with enterprise-grade durability. Your data is protected with encryption at rest and in transit, with blockchain-verified integrity.',
|
||||
features: [
|
||||
'S3-compatible API',
|
||||
'99.999999999% durability',
|
||||
'Encryption at rest and in transit',
|
||||
'Multi-region replication',
|
||||
'Versioning and lifecycle policies',
|
||||
],
|
||||
pricing: {
|
||||
storage: 0.023, // per GB/month
|
||||
egress: 0.09, // per GB
|
||||
currency: 'USD',
|
||||
},
|
||||
},
|
||||
'firebird-ai-engine': {
|
||||
name: 'Firebird AI Engine',
|
||||
category: 'AI & Machine Learning',
|
||||
description: 'AI that transforms like fire',
|
||||
longDescription: 'Firebird AI Engine provides scalable machine learning infrastructure with GPU acceleration, model training, and inference capabilities. Built for enterprise AI workloads.',
|
||||
features: [
|
||||
'GPU acceleration (NVIDIA A100/H100)',
|
||||
'Distributed training',
|
||||
'Model serving',
|
||||
'Auto-scaling inference',
|
||||
'MLOps integration',
|
||||
],
|
||||
pricing: {
|
||||
training: 2.50, // per GPU hour
|
||||
inference: 0.50, // per GPU hour
|
||||
currency: 'USD',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return Object.keys(products).map((slug) => ({ slug }))
|
||||
}
|
||||
|
||||
export default function ProductDetailPage({ params }: { params: { slug: string } }) {
|
||||
const product = products[params.slug as keyof typeof products]
|
||||
|
||||
if (!product) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Header */}
|
||||
<header className="border-b border-studio-medium bg-studio-dark">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
|
||||
<Link href="/" className="text-2xl font-bold text-white">
|
||||
<span className="text-sankofa-gold">Sankofa's</span> Phoenix <span className="text-phoenix-fire">Nexus</span> Cloud
|
||||
</Link>
|
||||
<nav className="flex gap-4">
|
||||
<Link href="/" className="text-gray-400 hover:text-white">
|
||||
Home
|
||||
</Link>
|
||||
<Link href="/products" className="text-gray-400 hover:text-white">
|
||||
Products
|
||||
</Link>
|
||||
<Link href="/about" className="text-gray-400 hover:text-white">
|
||||
About
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Breadcrumb */}
|
||||
<div className="mx-auto max-w-7xl px-4 py-4">
|
||||
<Link
|
||||
href="/products"
|
||||
className="inline-flex items-center gap-2 text-gray-400 hover:text-white"
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
Back to Products
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Product Detail */}
|
||||
<section className="mx-auto max-w-7xl px-4 py-12">
|
||||
<div className="grid gap-8 lg:grid-cols-2">
|
||||
{/* Product Info */}
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<span className="rounded-full bg-phoenix-fire/20 px-3 py-1 text-sm text-phoenix-fire">
|
||||
{product.category}
|
||||
</span>
|
||||
</div>
|
||||
<h1 className="mb-4 text-4xl font-bold text-white">{product.name}</h1>
|
||||
<p className="mb-6 text-xl text-gray-300">{product.description}</p>
|
||||
<p className="mb-8 text-gray-400">{product.longDescription}</p>
|
||||
|
||||
{/* Features */}
|
||||
<div className="mb-8">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Features</h2>
|
||||
<ul className="space-y-2">
|
||||
{product.features.map((feature, index) => (
|
||||
<li key={index} className="flex items-start gap-2 text-gray-300">
|
||||
<Check className="mt-1 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Pricing */}
|
||||
{product.pricing && (
|
||||
<div className="mb-8">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Pricing</h2>
|
||||
<Card className="border-studio-medium bg-studio-dark">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Pay-as-you-go</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{product.pricing.base && (
|
||||
<p className="text-gray-300">
|
||||
Base: ${product.pricing.base.toFixed(3)} per hour
|
||||
</p>
|
||||
)}
|
||||
{product.pricing.storage && (
|
||||
<p className="text-gray-300">
|
||||
Storage: ${product.pricing.storage.toFixed(3)} per GB/month
|
||||
</p>
|
||||
)}
|
||||
{product.pricing.training && (
|
||||
<p className="text-gray-300">
|
||||
Training: ${product.pricing.training.toFixed(2)} per GPU hour
|
||||
</p>
|
||||
)}
|
||||
{product.pricing.inference && (
|
||||
<p className="text-gray-300">
|
||||
Inference: ${product.pricing.inference.toFixed(2)} per GPU hour
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Tiers */}
|
||||
{product.tiers && (
|
||||
<div className="mb-8">
|
||||
<h2 className="mb-4 text-2xl font-bold text-white">Pricing Tiers</h2>
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
{product.tiers.map((tier, index) => (
|
||||
<Card key={index} className="border-studio-medium bg-studio-dark">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">{tier.name}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="mb-2 text-3xl font-bold text-phoenix-fire">
|
||||
${tier.price}
|
||||
<span className="text-sm text-gray-400">/month</span>
|
||||
</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
{tier.vcpu} vCPU, {tier.memory}GB RAM
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CTA */}
|
||||
<div className="flex gap-4">
|
||||
<Button variant="phoenix" size="lg">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="outline" size="lg">
|
||||
Contact Sales
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div>
|
||||
<Card className="border-studio-medium bg-studio-dark">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Ready to Start?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<p className="text-gray-400">
|
||||
Start building on Sankofa Phoenix today. No credit card required for free tier.
|
||||
</p>
|
||||
<Button variant="phoenix" className="w-full" size="lg">
|
||||
Create Account
|
||||
</Button>
|
||||
<Button variant="outline" className="w-full" size="lg">
|
||||
Schedule Demo
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
111
src/app/products/ai-ml/page.tsx
Normal file
111
src/app/products/ai-ml/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Sparkles, Brain, Network } from 'lucide-react'
|
||||
|
||||
export default function AIMLPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'Firebird AI Engine',
|
||||
icon: Sparkles,
|
||||
description: 'AI that transforms like fire',
|
||||
features: [
|
||||
'Model inference',
|
||||
'Real-time AI',
|
||||
'Edge AI deployment',
|
||||
'GPU acceleration',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Sankofa Memory Model',
|
||||
icon: Brain,
|
||||
description: 'AI models that remember and learn',
|
||||
features: [
|
||||
'Recursive learning',
|
||||
'Memory-augmented AI',
|
||||
'Context-aware models',
|
||||
'Continuous improvement',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Ancestral Neural Fabric',
|
||||
icon: Network,
|
||||
description: 'Distributed AI with ancestral patterns',
|
||||
features: [
|
||||
'Distributed training',
|
||||
'Federated learning',
|
||||
'Knowledge graphs',
|
||||
'Multi-region deployment',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
AI & Machine Learning
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
AI services powered by ancestral wisdom and modern technology
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
126
src/app/products/core-infrastructure/page.tsx
Normal file
126
src/app/products/core-infrastructure/page.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Server, HardDrive, Network } from 'lucide-react'
|
||||
|
||||
export default function CoreInfrastructurePage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'PhoenixCore Compute',
|
||||
icon: Server,
|
||||
description: 'Core compute engine powered by Phoenix fire',
|
||||
features: [
|
||||
'Virtual machines and containers',
|
||||
'Serverless functions',
|
||||
'Auto-scaling capabilities',
|
||||
'Multi-region deployment',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'OkraVault Storage',
|
||||
icon: HardDrive,
|
||||
description: 'Storage for the soul of your data',
|
||||
features: [
|
||||
'Object and block storage',
|
||||
'High-performance NVMe storage',
|
||||
'Multi-region replication',
|
||||
'S3-compatible API',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'SankofaGrid Global Mesh',
|
||||
icon: Network,
|
||||
description: 'Global network mesh that remembers',
|
||||
features: [
|
||||
'325-region global network',
|
||||
'Low-latency routing',
|
||||
'Private network connections',
|
||||
'DDoS protection',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
{/* Hero Section */}
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Core Infrastructure
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
The foundation of sovereign cloud infrastructure
|
||||
</p>
|
||||
|
||||
<p className="mb-12 text-lg text-gray-400">
|
||||
Compute, storage, and networking services that power the Phoenix Nexus Cloud
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Products Grid */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Build on sovereign cloud infrastructure
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/docs">View Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
111
src/app/products/data/page.tsx
Normal file
111
src/app/products/data/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Database, Layers, Clock } from 'lucide-react'
|
||||
|
||||
export default function DataServicesPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'SankofaGraph Database',
|
||||
icon: Database,
|
||||
description: 'Graph database that remembers relationships',
|
||||
features: [
|
||||
'Knowledge graphs',
|
||||
'Relationship mapping',
|
||||
'Network analysis',
|
||||
'GraphQL interface',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'PhoenixFire NoSQL',
|
||||
icon: Layers,
|
||||
description: 'Fast, powerful NoSQL database',
|
||||
features: [
|
||||
'Document stores',
|
||||
'Key-value stores',
|
||||
'High-performance queries',
|
||||
'Auto-scaling',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Nananom Time Series',
|
||||
icon: Clock,
|
||||
description: 'Time-series database for historical data',
|
||||
features: [
|
||||
'Metrics storage',
|
||||
'Monitoring data',
|
||||
'Historical analysis',
|
||||
'High-throughput ingestion',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Data Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Databases and data services for modern applications
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
100
src/app/products/developer/page.tsx
Normal file
100
src/app/products/developer/page.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Code, Hammer } from 'lucide-react'
|
||||
|
||||
export default function DeveloperServicesPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'SankofaDev Platform',
|
||||
icon: Code,
|
||||
description: 'Development that remembers best practices',
|
||||
features: [
|
||||
'CI/CD pipelines',
|
||||
'Developer tools',
|
||||
'Platform services',
|
||||
'GitOps workflows',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'PhoenixForge Build Engine',
|
||||
icon: Hammer,
|
||||
description: 'Build and deployment services',
|
||||
features: [
|
||||
'Build systems',
|
||||
'Deployment automation',
|
||||
'Container builds',
|
||||
'Artifact management',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Developer Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Tools and services for modern development workflows
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
100
src/app/products/identity/page.tsx
Normal file
100
src/app/products/identity/page.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { User, Key } from 'lucide-react'
|
||||
|
||||
export default function IdentityPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'OkraID',
|
||||
icon: User,
|
||||
description: 'Soul-powered identity framework',
|
||||
features: [
|
||||
'Self-sovereign identity',
|
||||
'Decentralized identity',
|
||||
'User authentication',
|
||||
'Identity verification',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'AkanAuth Sovereign Identity Plane',
|
||||
icon: Key,
|
||||
description: 'Sovereign authentication platform',
|
||||
features: [
|
||||
'Multi-factor authentication',
|
||||
'Single sign-on (SSO)',
|
||||
'Identity federation',
|
||||
'Sovereign identity management',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Identity Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Sovereign identity management for the modern web
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
100
src/app/products/management/page.tsx
Normal file
100
src/app/products/management/page.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Settings, Globe2 } from 'lucide-react'
|
||||
|
||||
export default function ManagementPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'SankofaControl Plane',
|
||||
icon: Settings,
|
||||
description: 'Control that remembers and learns',
|
||||
features: [
|
||||
'Infrastructure as Code',
|
||||
'Orchestration',
|
||||
'Resource management',
|
||||
'Policy enforcement',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'PhoenixRealm Management',
|
||||
icon: Globe2,
|
||||
description: 'Multi-cloud and multi-region management',
|
||||
features: [
|
||||
'Multi-cloud management',
|
||||
'Global orchestration',
|
||||
'Region management',
|
||||
'Unified control plane',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Management Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Infrastructure management and orchestration for global deployments
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
111
src/app/products/networking/page.tsx
Normal file
111
src/app/products/networking/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Network, Globe, Zap } from 'lucide-react'
|
||||
|
||||
export default function NetworkingPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'SankofaGrid Global Mesh',
|
||||
icon: Network,
|
||||
description: 'Global network mesh that remembers',
|
||||
features: [
|
||||
'325-region global network',
|
||||
'Low-latency routing',
|
||||
'Private network connections',
|
||||
'Multi-region connectivity',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'AkanSphere Edge Routing',
|
||||
icon: Globe,
|
||||
description: 'Edge routing with cultural intelligence',
|
||||
features: [
|
||||
'Edge routing',
|
||||
'Traffic management',
|
||||
'CDN integration',
|
||||
'Geographic routing',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'PhoenixFlight Network Fabric',
|
||||
icon: Zap,
|
||||
description: 'High-performance network fabric',
|
||||
features: [
|
||||
'High-bandwidth connections',
|
||||
'Data center networking',
|
||||
'Low-latency fabric',
|
||||
'Network automation',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Networking Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Global networking infrastructure for sovereign cloud
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function ProductsPage() {
|
||||
<header className="border-b border-studio-medium bg-studio-dark">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
|
||||
<Link href="/" className="text-2xl font-bold text-white">
|
||||
Phoenix <span className="text-phoenix-fire">Sankofa</span> Cloud
|
||||
<span className="text-sankofa-gold">Sankofa's</span> Phoenix <span className="text-phoenix-fire">Nexus</span> Cloud
|
||||
</Link>
|
||||
<nav className="flex gap-4">
|
||||
<Link href="/" className="text-gray-400 hover:text-white">
|
||||
@@ -96,18 +96,26 @@ export default function ProductsPage() {
|
||||
{category.category}
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
{category.items.map((item) => (
|
||||
<Card key={item.name}>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">{item.name}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardDescription className="text-gray-400">
|
||||
{item.description}
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
{category.items.map((item) => {
|
||||
const slug = item.name.toLowerCase().replace(/\s+/g, '-')
|
||||
return (
|
||||
<Card key={item.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">{item.name}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardDescription className="text-gray-400 mb-4">
|
||||
{item.description}
|
||||
</CardDescription>
|
||||
<Link href={`/products/${slug}`}>
|
||||
<Button variant="outline" size="sm" className="w-full">
|
||||
Learn More
|
||||
</Button>
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
111
src/app/products/security/page.tsx
Normal file
111
src/app/products/security/page.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Shield, Lock, Eye } from 'lucide-react'
|
||||
|
||||
export default function SecurityPage() {
|
||||
const products = [
|
||||
{
|
||||
name: 'Aegis of Akan Shield',
|
||||
icon: Shield,
|
||||
description: 'Comprehensive security platform',
|
||||
features: [
|
||||
'Threat protection',
|
||||
'DDoS mitigation',
|
||||
'Security monitoring',
|
||||
'Zero Trust networking',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'PhoenixGuard IAM',
|
||||
icon: Lock,
|
||||
description: 'Identity and access management',
|
||||
features: [
|
||||
'Multi-factor authentication',
|
||||
'Single sign-on (SSO)',
|
||||
'Role-based access control',
|
||||
'Identity federation',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Nsamankom Sentinel',
|
||||
icon: Eye,
|
||||
description: 'Security monitoring with ancestral protection',
|
||||
features: [
|
||||
'Security monitoring',
|
||||
'Threat detection',
|
||||
'Compliance reporting',
|
||||
'Incident response',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black">
|
||||
<section className="relative flex min-h-[50vh] flex-col items-center justify-center overflow-hidden px-4">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-phoenix-fire/20 via-transparent to-sankofa-gold/20" />
|
||||
|
||||
<div className="relative z-10 max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
|
||||
Security Services
|
||||
</h1>
|
||||
|
||||
<p className="mb-8 text-xl text-gray-300 md:text-2xl">
|
||||
Enterprise-grade security for sovereign cloud infrastructure
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const Icon = product.icon
|
||||
return (
|
||||
<Card key={product.name} className="hover:border-phoenix-fire transition-colors">
|
||||
<CardHeader>
|
||||
<Icon className="mb-4 h-12 w-12 text-phoenix-fire" />
|
||||
<CardTitle className="text-xl">{product.name}</CardTitle>
|
||||
<CardDescription className="text-gray-400">
|
||||
{product.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300 mb-6">
|
||||
{product.features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2">
|
||||
<span className="text-phoenix-fire mt-1">•</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button variant="outline" className="w-full" asChild>
|
||||
<Link href={`/products/${product.name.toLowerCase().replace(/\s+/g, '-')}`}>
|
||||
Learn More
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="py-24 px-4 bg-studio-dark">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal">Get Started</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import { ApolloProvider } from '@apollo/client'
|
||||
import { apolloClient } from '@/lib/graphql/client'
|
||||
import { getApolloClient } from '@/lib/graphql/client'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import { useState, useMemo } from 'react'
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||
import { Toaster } from '@/components/ui/toaster'
|
||||
|
||||
@@ -33,6 +33,9 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
||||
})
|
||||
)
|
||||
|
||||
// Create Apollo Client only on client side
|
||||
const apolloClient = useMemo(() => getApolloClient(), [])
|
||||
|
||||
return (
|
||||
<ApolloProvider client={apolloClient}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
|
||||
183
src/app/solutions/enterprise/page.tsx
Normal file
183
src/app/solutions/enterprise/page.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Check, Shield, Globe, Lock, Zap, Users } from 'lucide-react'
|
||||
|
||||
export default function EnterprisePage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Enterprise Cloud Infrastructure
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Sovereign cloud infrastructure designed for enterprise scale, security, and compliance
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/get-started">Start Free Trial</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/company/trust">View Compliance</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Trust & Compliance */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Enterprise-Grade Trust & Compliance
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Security First</CardTitle>
|
||||
<CardDescription>
|
||||
DoD/MilSpec compliance, zero-trust architecture, and sovereign identity management
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>STIG-compliant infrastructure</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Keycloak-based sovereign identity (no Azure dependencies)</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>End-to-end encryption</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Lock className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Compliance Ready</CardTitle>
|
||||
<CardDescription>
|
||||
Built for regulated industries and government requirements
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>RMF authorization ready</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Audit logging and compliance reporting</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Data sovereignty controls</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Globe className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Global Infrastructure</CardTitle>
|
||||
<CardDescription>
|
||||
325-region deployment with edge computing and regional data residency
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Multi-region redundancy</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Edge computing for low latency</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Check className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Data residency controls</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Enterprise Features */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Enterprise Capabilities
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<Zap className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Advanced Multi-Tenancy</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Superior tenant isolation, per-second billing granularity, and comprehensive quota management.
|
||||
Built for enterprises managing multiple business units or customer tenants.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Tenant-level resource isolation</li>
|
||||
<li>• Per-second billing with cost forecasting</li>
|
||||
<li>• Budget management and alerts</li>
|
||||
<li>• Custom quota enforcement</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Users className="mb-4 h-8 w-8 text-sankofa-gold" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Role-Based Access Control</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Enterprise-grade RBAC with fine-grained permissions, audit trails, and integration
|
||||
with your existing identity providers.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Custom roles and permissions</li>
|
||||
<li>• SSO integration (SAML, OIDC)</li>
|
||||
<li>• Audit logging for all actions</li>
|
||||
<li>• Multi-factor authentication</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Transform Your Infrastructure?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Join enterprises leveraging sovereign cloud infrastructure
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/get-started">Contact Sales</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/developers">View Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
169
src/app/solutions/government/page.tsx
Normal file
169
src/app/solutions/government/page.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { Shield, Lock, FileCheck, Globe, CheckCircle, Building2 } from 'lucide-react'
|
||||
|
||||
export default function GovernmentPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Government Cloud Infrastructure
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Sovereign cloud infrastructure designed for government agencies and public sector organizations
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/get-started">Request Demo</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/company/trust">View Compliance</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Government Features */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Built for Government Requirements
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>DoD/MilSpec Compliance</CardTitle>
|
||||
<CardDescription>
|
||||
STIG-compliant infrastructure meeting Department of Defense standards
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Security Technical Implementation Guides (STIG)</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>RMF authorization ready</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>FedRAMP alignment (in progress)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Lock className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Data Sovereignty</CardTitle>
|
||||
<CardDescription>
|
||||
Complete control over data location and access
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>On-premises deployment options</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Air-gapped configurations</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Regional data residency controls</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<FileCheck className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Audit & Compliance</CardTitle>
|
||||
<CardDescription>
|
||||
Comprehensive audit logging and compliance reporting
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Immutable audit logs</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Compliance dashboards</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Automated compliance reporting</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Building2 className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Government Partnerships</CardTitle>
|
||||
<CardDescription>
|
||||
Dedicated support for government agencies
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Dedicated government support team</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>GSA schedule (in progress)</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Custom contract vehicles</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Transform Government IT?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Contact our government team to learn more
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/support">Contact Government Team</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/developers">View Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
183
src/app/solutions/institutional/page.tsx
Normal file
183
src/app/solutions/institutional/page.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { GraduationCap, Users, Shield, BookOpen, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function InstitutionalPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Institutional Cloud Infrastructure
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Sovereign cloud infrastructure for educational institutions, research organizations, and non-profits
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/portal/get-started">Get Started</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/solutions/institutional/pricing">View Pricing</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Institutional Features */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Built for Institutions
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<GraduationCap className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Education-Focused</CardTitle>
|
||||
<CardDescription>
|
||||
Designed for universities, colleges, and research institutions
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Student and faculty management</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Research computing resources</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-phoenix-fire" />
|
||||
<span>Academic pricing and discounts</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Users className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Multi-Tenant Support</CardTitle>
|
||||
<CardDescription>
|
||||
Manage multiple departments, schools, or research groups
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Department-level isolation</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Budget allocation and tracking</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-sankofa-gold" />
|
||||
<span>Usage reporting by department</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Privacy & Security</CardTitle>
|
||||
<CardDescription>
|
||||
FERPA and HIPAA considerations for educational data
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Data privacy controls</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Secure research environments</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-neon-cyan" />
|
||||
<span>Compliance with educational regulations</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Use Cases */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Institutional Use Cases
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<BookOpen className="mb-4 h-8 w-8 text-phoenix-fire" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Research Computing</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
High-performance computing resources for research projects,
|
||||
data analysis, and computational research.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• GPU clusters for ML/AI research</li>
|
||||
<li>• Large-scale data processing</li>
|
||||
<li>• Collaborative research environments</li>
|
||||
<li>• Research data management</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Users className="mb-4 h-8 w-8 text-sankofa-gold" />
|
||||
<h3 className="mb-4 text-2xl font-bold text-white">Campus IT Infrastructure</h3>
|
||||
<p className="mb-4 text-gray-300">
|
||||
Modern cloud infrastructure for campus-wide IT services,
|
||||
student portals, and administrative systems.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li>• Student information systems</li>
|
||||
<li>• Learning management systems</li>
|
||||
<li>• Campus-wide applications</li>
|
||||
<li>• Administrative computing</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Ready to Modernize Your Institution?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Contact our institutional team to learn more
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-center">
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/support">Contact Institutional Team</Link>
|
||||
</Button>
|
||||
<Button variant="outline" size="lg" asChild>
|
||||
<Link href="/developers">View Documentation</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
179
src/app/support/page.tsx
Normal file
179
src/app/support/page.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Header } from '@/components/layout/header'
|
||||
import { HelpCircle, Book, MessageSquare, FileText, Search, Headphones } from 'lucide-react'
|
||||
|
||||
export default function SupportPage() {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main className="min-h-screen bg-studio-black">
|
||||
{/* Hero */}
|
||||
<section className="relative border-b border-studio-medium bg-gradient-to-br from-phoenix-fire/10 via-transparent to-sankofa-gold/10 py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h1 className="mb-6 text-5xl font-bold text-white md:text-6xl">
|
||||
Support Center
|
||||
</h1>
|
||||
<p className="mb-8 text-xl text-gray-300">
|
||||
Get help when you need it
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Support Options */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
How Can We Help?
|
||||
</h2>
|
||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/developers/docs">
|
||||
<CardHeader>
|
||||
<Book className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>Documentation</CardTitle>
|
||||
<CardDescription>
|
||||
Comprehensive guides, API references, and tutorials
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/support/kb">
|
||||
<CardHeader>
|
||||
<FileText className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Knowledge Base</CardTitle>
|
||||
<CardDescription>
|
||||
Search articles, FAQs, and troubleshooting guides
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/support/contact">
|
||||
<CardHeader>
|
||||
<MessageSquare className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Contact Support</CardTitle>
|
||||
<CardDescription>
|
||||
Get in touch with our support team
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/support/status">
|
||||
<CardHeader>
|
||||
<Search className="mb-2 h-10 w-10 text-phoenix-fire" />
|
||||
<CardTitle>System Status</CardTitle>
|
||||
<CardDescription>
|
||||
Check service status and incident reports
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/support/community">
|
||||
<CardHeader>
|
||||
<Headphones className="mb-2 h-10 w-10 text-sankofa-gold" />
|
||||
<CardTitle>Community</CardTitle>
|
||||
<CardDescription>
|
||||
Connect with other users and experts
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
|
||||
<Card className="hover:border-phoenix-fire transition-colors cursor-pointer" asChild>
|
||||
<Link href="/support/training">
|
||||
<CardHeader>
|
||||
<HelpCircle className="mb-2 h-10 w-10 text-neon-cyan" />
|
||||
<CardTitle>Training</CardTitle>
|
||||
<CardDescription>
|
||||
Learn through courses and workshops
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Support Tiers */}
|
||||
<section className="border-t border-studio-medium bg-studio-dark py-24 px-4">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<h2 className="mb-12 text-center text-4xl font-bold text-white">
|
||||
Support Plans
|
||||
</h2>
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Community Support</CardTitle>
|
||||
<CardDescription>Free</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Community forums</li>
|
||||
<li>• Documentation access</li>
|
||||
<li>• Knowledge base</li>
|
||||
<li>• Best effort responses</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-phoenix-fire">
|
||||
<CardHeader>
|
||||
<CardTitle>Standard Support</CardTitle>
|
||||
<CardDescription>Included with subscription</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• Email support (24-48h response)</li>
|
||||
<li>• Priority documentation access</li>
|
||||
<li>• System status notifications</li>
|
||||
<li>• Business hours support</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Enterprise Support</CardTitle>
|
||||
<CardDescription>Premium</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li>• 24/7 phone and email support</li>
|
||||
<li>• Dedicated support engineer</li>
|
||||
<li>• SLA guarantees</li>
|
||||
<li>• On-site support available</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="py-24 px-4">
|
||||
<div className="mx-auto max-w-4xl text-center">
|
||||
<h2 className="mb-6 text-4xl font-bold text-white">
|
||||
Need Immediate Help?
|
||||
</h2>
|
||||
<p className="mb-8 text-xl text-gray-400">
|
||||
Contact our support team
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<Link href="/support/contact">Contact Support</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
107
src/app/white-label/page.tsx
Normal file
107
src/app/white-label/page.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import { PublicLayout } from '@/components/layout/public-layout'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Palette, Globe, Shield, CheckCircle } from 'lucide-react'
|
||||
|
||||
export default function WhiteLabelPage() {
|
||||
return (
|
||||
<PublicLayout>
|
||||
<div className="min-h-screen bg-studio-black py-24 px-4">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-12 text-center">
|
||||
<h1 className="mb-4 text-5xl font-bold text-white">White-Label Solution</h1>
|
||||
<p className="text-xl text-gray-400">
|
||||
Customize Phoenix with your brand for enterprise deployments
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Palette className="h-8 w-8 text-phoenix-fire mb-2" />
|
||||
<CardTitle className="text-white">Custom Branding</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Custom logo and colors</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Custom domain</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Branded email templates</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Globe className="h-8 w-8 text-sankofa-gold mb-2" />
|
||||
<CardTitle className="text-white">Multi-Tenant</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Isolated tenant environments</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Custom subdomains</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Tenant-specific branding</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Shield className="h-8 w-8 text-neon-cyan mb-2" />
|
||||
<CardTitle className="text-white">Enterprise Features</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2 text-sm text-gray-300">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>SLA guarantees</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Dedicated support</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle className="h-4 w-4 text-green-400" />
|
||||
<span>Custom integrations</span>
|
||||
</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="bg-studio-dark border-studio-medium">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white">Get Started with White-Label</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-gray-300 mb-6">
|
||||
Contact our enterprise sales team to discuss white-label options for your organization.
|
||||
</p>
|
||||
<Button variant="phoenix" size="lg" asChild>
|
||||
<a href="/enterprise">Contact Sales</a>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</PublicLayout>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user