Set up Cloudflare Pages deployment with BlackRoad-branded dashboard

- Convert Next.js dashboard from standalone to static export for CF Pages
- Update design tokens, Button, and Card components to official brand colors
  (hot pink, amber, violet, electric blue with golden ratio spacing)
- Replace generic service page with infra dashboard showing deploy/setup stats,
  Terraform/CI/Docker/Operations sections, and network topology
- Remove API routes (incompatible with static export)
- Add wrangler.toml and postcss.config.js
- Deployed to blackroad-infra.pages.dev

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alexa Amundson
2026-02-21 02:01:04 -06:00
parent cc4cfa90d5
commit 987fd379bb
13 changed files with 795 additions and 360 deletions

View File

@@ -1,12 +0,0 @@
import { NextResponse } from 'next/server'
export async function GET() {
const serviceName = process.env.SERVICE_NAME || 'blackroad-service'
return NextResponse.json({
status: 'ok',
service: serviceName,
timestamp: new Date().toISOString(),
uptime: process.uptime()
})
}

View File

@@ -1,18 +0,0 @@
import { NextResponse } from 'next/server'
export async function GET() {
// Add any readiness checks here (database connections, external services, etc.)
const isReady = true
if (!isReady) {
return NextResponse.json(
{ ready: false, reason: 'Service dependencies not available' },
{ status: 503 }
)
}
return NextResponse.json({
ready: true,
service: process.env.SERVICE_NAME || 'blackroad-service'
})
}

View File

@@ -1,15 +0,0 @@
import { NextResponse } from 'next/server'
export async function GET() {
const serviceName = process.env.SERVICE_NAME || 'blackroad-service'
const version = process.env.SERVICE_VERSION || '0.0.1'
const environment = process.env.SERVICE_ENV || 'development'
return NextResponse.json({
version,
service: serviceName,
environment,
node_version: process.version,
build_time: process.env.BUILD_TIME || new Date().toISOString()
})
}

View File

@@ -1,95 +1,18 @@
* { * {
box-sizing: border-box;
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box;
} }
html,
body { body {
max-width: 100vw; background: #000;
overflow-x: hidden; color: #e0e0e0;
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
@keyframes fadeIn { ::selection {
from { background: rgba(255, 29, 108, 0.3);
opacity: 0; color: #fff;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
transform: translateX(-10px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.8;
}
}
.animate-fade-in {
animation: fadeIn 0.5s ease-out;
}
.animate-slide-in {
animation: slideIn 0.4s ease-out;
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
a {
color: inherit;
text-decoration: none;
}
button {
font-family: inherit;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Focus styles for accessibility */
*:focus-visible {
outline: 2px solid #667eea;
outline-offset: 2px;
}
/* Loading skeleton */
@keyframes skeleton {
0% {
background-position: -200px 0;
}
100% {
background-position: calc(200px + 100%) 0;
}
}
.skeleton {
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0.05) 0px,
rgba(255, 255, 255, 0.1) 40px,
rgba(255, 255, 255, 0.05) 80px
);
background-size: 200px 100%;
animation: skeleton 1.2s ease-in-out infinite;
} }

View File

@@ -1,8 +1,12 @@
import type { Metadata } from 'next' import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = { export const metadata: Metadata = {
title: process.env.NEXT_PUBLIC_APP_NAME || 'BlackRoad Service', title: 'BlackRoad Infrastructure',
description: 'BlackRoad infrastructure service', description: 'Deployment automation, CI/CD workflows, Terraform modules, and infrastructure-as-code for the BlackRoad OS distributed network.',
icons: {
icon: 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">🛤️</text></svg>',
},
} }
export default function RootLayout({ export default function RootLayout({
@@ -12,12 +16,7 @@ export default function RootLayout({
}) { }) {
return ( return (
<html lang="en"> <html lang="en">
<body style={{ <body>
margin: 0,
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
backgroundColor: '#0a0a0a',
color: '#e0e0e0'
}}>
{children} {children}
</body> </body>
</html> </html>

View File

@@ -1,8 +1,4 @@
export default function Home() { export default function Home() {
const serviceName = process.env.SERVICE_NAME || 'blackroad-service'
const serviceEnv = process.env.SERVICE_ENV || 'development'
const appName = process.env.NEXT_PUBLIC_APP_NAME || 'BlackRoad Service'
return ( return (
<main style={{ <main style={{
minHeight: '100vh', minHeight: '100vh',
@@ -10,136 +6,198 @@ export default function Home() {
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
padding: '2rem' padding: '34px',
}}> }}>
<div style={{ <div style={{ maxWidth: '900px', width: '100%' }}>
maxWidth: '800px',
width: '100%',
padding: '2rem',
backgroundColor: '#1a1a1a',
borderRadius: '8px',
border: '1px solid #333'
}}>
<h1 style={{ <h1 style={{
fontSize: '2.5rem', fontSize: '2.5rem',
marginBottom: '0.5rem', marginBottom: '13px',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', background: 'linear-gradient(135deg, #F5A623 0%, #FF1D6C 38.2%, #9C27B0 61.8%, #2979FF 100%)',
WebkitBackgroundClip: 'text', WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent', WebkitTextFillColor: 'transparent',
backgroundClip: 'text' backgroundClip: 'text',
fontWeight: 700,
}}> }}>
{appName} BlackRoad Infrastructure
</h1> </h1>
<div style={{
display: 'flex',
gap: '1rem',
marginBottom: '2rem',
fontSize: '0.875rem'
}}>
<span style={{
padding: '0.25rem 0.75rem',
backgroundColor: '#2a2a2a',
borderRadius: '4px',
border: '1px solid #444'
}}>
{serviceName}
</span>
<span style={{
padding: '0.25rem 0.75rem',
backgroundColor: serviceEnv === 'production' ? '#1a472a' : '#2a2a2a',
borderRadius: '4px',
border: `1px solid ${serviceEnv === 'production' ? '#2d5f3d' : '#444'}`
}}>
{serviceEnv}
</span>
</div>
<p style={{ <p style={{
fontSize: '1.125rem', fontSize: '1.1rem',
lineHeight: '1.75', color: '#999',
marginBottom: '2rem', marginBottom: '55px',
color: '#b0b0b0' lineHeight: 1.618,
}}> }}>
BlackRoad infrastructure service endpoint. This service is part of the BlackRoad ecosystem. Deployment automation, CI/CD workflows, Terraform modules, and infrastructure-as-code for the BlackRoad OS distributed network.
</p> </p>
<div style={{ <div style={{
display: 'grid', display: 'grid',
gap: '1rem', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
marginTop: '2rem' gap: '21px',
marginBottom: '55px',
}}> }}>
<h2 style={{ <StatCard label="Deploy Scripts" value="94" desc="Automated pipelines" color="#FF1D6C" />
fontSize: '1.25rem', <StatCard label="Setup Scripts" value="32" desc="Configuration automation" color="#F5A623" />
marginBottom: '0.5rem', <StatCard label="Terraform Modules" value="IaC" desc="Multi-cloud provisioning" color="#9C27B0" />
color: '#e0e0e0' <StatCard label="Fleet Devices" value="8" desc="Connected nodes" color="#2979FF" />
</div>
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
gap: '21px',
marginBottom: '55px',
}}>
<SectionCard
title="Terraform"
items={[
'Cloudflare DNS & Pages modules',
'DigitalOcean droplet provisioning',
'Railway service orchestration',
'Production & staging environments',
]}
/>
<SectionCard
title="CI / CD"
items={[
'Reusable GitHub Actions workflows',
'Composite action templates',
'Auto-deploy on push to main',
'Multi-environment promotion',
]}
/>
<SectionCard
title="Docker"
items={[
'Multi-service compose stacks',
'Optimized production images',
'Health check integration',
'Container orchestration',
]}
/>
<SectionCard
title="Operations"
items={[
'Fleet SSH management',
'Tailscale mesh networking',
'Monitoring & alerting',
'Backup & disaster recovery',
]}
/>
</div>
<div style={{
background: '#111',
border: '1px solid #222',
borderRadius: '13px',
padding: '21px',
marginBottom: '55px',
}}>
<h3 style={{
color: '#F5A623',
fontSize: '0.85rem',
textTransform: 'uppercase',
letterSpacing: '1px',
marginBottom: '13px',
}}> }}>
Service Endpoints Network Topology
</h2> </h3>
<div style={{
<a fontFamily: "'SF Mono', Monaco, Consolas, monospace",
href="/api/health" fontSize: '0.8rem',
style={{ color: '#666',
display: 'block', lineHeight: 1.8,
padding: '1rem', }}>
backgroundColor: '#2a2a2a', <div><span style={{color:'#FF1D6C'}}>alexandria</span> <span style={{color:'#444'}}></span> Mac host <span style={{color:'#444'}}></span> orchestrator</div>
borderRadius: '6px', <div><span style={{color:'#F5A623'}}>cecilia</span> <span style={{color:'#444'}}></span> Pi 5 + Hailo-8 (26 TOPS) <span style={{color:'#444'}}></span> primary AI agent</div>
border: '1px solid #444', <div><span style={{color:'#9C27B0'}}>lucidia</span> <span style={{color:'#444'}}></span> Pi 5 + Pironman + 1TB NVMe <span style={{color:'#444'}}></span> inference</div>
textDecoration: 'none', <div><span style={{color:'#2979FF'}}>octavia</span> <span style={{color:'#444'}}></span> Pi 5 <span style={{color:'#444'}}></span> multi-arm processing</div>
color: '#667eea', <div><span style={{color:'#4ade80'}}>alice</span> <span style={{color:'#444'}}></span> Pi 4 <span style={{color:'#444'}}></span> worker node</div>
transition: 'all 0.2s' <div><span style={{color:'#FF1D6C'}}>aria</span> <span style={{color:'#444'}}></span> Pi 5 <span style={{color:'#444'}}></span> harmony protocols</div>
}} <div><span style={{color:'#F5A623'}}>shellfish</span> <span style={{color:'#444'}}></span> DigitalOcean <span style={{color:'#444'}}></span> edge compute</div>
> <div><span style={{color:'#9C27B0'}}>infinity</span> <span style={{color:'#444'}}></span> DigitalOcean <span style={{color:'#444'}}></span> cloud oracle</div>
<strong>/api/health</strong> </div>
<span style={{ color: '#888', marginLeft: '1rem' }}> Health check endpoint</span>
</a>
<a
href="/api/version"
style={{
display: 'block',
padding: '1rem',
backgroundColor: '#2a2a2a',
borderRadius: '6px',
border: '1px solid #444',
textDecoration: 'none',
color: '#667eea',
transition: 'all 0.2s'
}}
>
<strong>/api/version</strong>
<span style={{ color: '#888', marginLeft: '1rem' }}> Version information</span>
</a>
<a
href="/api/ready"
style={{
display: 'block',
padding: '1rem',
backgroundColor: '#2a2a2a',
borderRadius: '6px',
border: '1px solid #444',
textDecoration: 'none',
color: '#667eea',
transition: 'all 0.2s'
}}
>
<strong>/api/ready</strong>
<span style={{ color: '#888', marginLeft: '1rem' }}> Readiness probe</span>
</a>
</div> </div>
<footer style={{ <footer style={{
marginTop: '3rem', textAlign: 'center',
paddingTop: '1.5rem', color: '#444',
borderTop: '1px solid #333', fontSize: '0.75rem',
fontSize: '0.875rem', paddingTop: '21px',
color: '#666', borderTop: '1px solid #1a1a1a',
textAlign: 'center'
}}> }}>
BlackRoad Infrastructure · {new Date().getFullYear()} &copy; 2025&ndash;2026 BlackRoad OS, Inc. All Rights Reserved.
</footer> </footer>
</div> </div>
</main> </main>
) )
} }
function StatCard({ label, value, desc, color }: { label: string; value: string; desc: string; color: string }) {
return (
<div style={{
background: '#111',
border: '1px solid #222',
borderRadius: '13px',
padding: '21px',
}}>
<h3 style={{
color,
fontSize: '0.8rem',
textTransform: 'uppercase',
letterSpacing: '1px',
marginBottom: '8px',
}}>
{label}
</h3>
<div style={{ fontSize: '1.8rem', fontWeight: 700, color: '#fff', marginBottom: '4px' }}>
{value}
</div>
<div style={{ color: '#666', fontSize: '0.85rem' }}>{desc}</div>
</div>
)
}
function SectionCard({ title, items }: { title: string; items: string[] }) {
return (
<div style={{
background: '#111',
border: '1px solid #222',
borderRadius: '13px',
padding: '21px',
}}>
<h3 style={{
color: '#FF1D6C',
fontSize: '0.9rem',
textTransform: 'uppercase',
letterSpacing: '1px',
marginBottom: '13px',
}}>
{title}
</h3>
<ul style={{
listStyle: 'none',
padding: 0,
margin: 0,
}}>
{items.map((item, i) => (
<li key={i} style={{
color: '#999',
fontSize: '0.85rem',
lineHeight: 1.618,
paddingLeft: '13px',
position: 'relative',
}}>
<span style={{
position: 'absolute',
left: 0,
color: '#444',
}}>
</span>
{item}
</li>
))}
</ul>
</div>
)
}

View File

@@ -48,24 +48,24 @@ const getButtonStyles = (variant: ButtonVariant, size: ButtonSize, disabled: boo
const variantStyles: Record<ButtonVariant, CSSProperties> = { const variantStyles: Record<ButtonVariant, CSSProperties> = {
primary: { primary: {
background: gradients.primary, background: gradients.brand,
color: 'white', color: 'white',
boxShadow: '0 4px 15px rgba(102, 126, 234, 0.4)', boxShadow: '0 4px 15px rgba(255, 29, 108, 0.4)',
}, },
secondary: { secondary: {
background: gradients.secondary, background: gradients.pinkToViolet,
color: 'white', color: 'white',
boxShadow: '0 4px 15px rgba(240, 147, 251, 0.4)', boxShadow: '0 4px 15px rgba(156, 39, 176, 0.4)',
}, },
tertiary: { tertiary: {
background: gradients.tertiary, background: gradients.blueToViolet,
color: 'white', color: 'white',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)', boxShadow: '0 4px 15px rgba(41, 121, 255, 0.4)',
}, },
ghost: { ghost: {
background: 'transparent', background: 'transparent',
color: colors.primary.purple, color: colors.brand.hotPink,
border: `2px solid ${colors.primary.purple}`, border: `2px solid ${colors.brand.hotPink}`,
}, },
danger: { danger: {
background: colors.semantic.error, background: colors.semantic.error,
@@ -87,12 +87,6 @@ export function Button({
style style
}: ButtonProps) { }: ButtonProps) {
const buttonStyles = getButtonStyles(variant, size, disabled) const buttonStyles = getButtonStyles(variant, size, disabled)
const hoverStyles = !disabled ? {
':hover': {
transform: 'translateY(-2px)',
boxShadow: shadows['2xl']
}
} : {}
if (href) { if (href) {
return ( return (
@@ -102,7 +96,7 @@ export function Button({
onMouseEnter={(e) => { onMouseEnter={(e) => {
if (!disabled) { if (!disabled) {
e.currentTarget.style.transform = 'translateY(-2px)' e.currentTarget.style.transform = 'translateY(-2px)'
e.currentTarget.style.boxShadow = shadows['2xl'] e.currentTarget.style.boxShadow = shadows.xl
} }
}} }}
onMouseLeave={(e) => { onMouseLeave={(e) => {
@@ -122,7 +116,7 @@ export function Button({
onMouseEnter={(e) => { onMouseEnter={(e) => {
if (!disabled) { if (!disabled) {
e.currentTarget.style.transform = 'translateY(-2px)' e.currentTarget.style.transform = 'translateY(-2px)'
e.currentTarget.style.boxShadow = shadows['2xl'] e.currentTarget.style.boxShadow = shadows.xl
} }
}} }}
onMouseLeave={(e) => { onMouseLeave={(e) => {

View File

@@ -19,29 +19,31 @@ export function Card({
hoverable = false hoverable = false
}: CardProps) { }: CardProps) {
const baseStyles: CSSProperties = { const baseStyles: CSSProperties = {
padding: '2rem', padding: '21px',
borderRadius: borderRadius.xl, borderRadius: borderRadius.lg,
transition: transitions.normal, transition: transitions.normal,
cursor: onClick ? 'pointer' : 'default' cursor: onClick ? 'pointer' : 'default'
} }
const variantStyles: Record<string, CSSProperties> = { const variantStyles: Record<string, CSSProperties> = {
default: { default: {
backgroundColor: '#ffffff', backgroundColor: '#111',
border: '1px solid #222',
boxShadow: shadows.md, boxShadow: shadows.md,
}, },
elevated: { elevated: {
backgroundColor: '#ffffff', backgroundColor: '#111',
boxShadow: shadows['2xl'], border: '1px solid #222',
boxShadow: shadows.xl,
}, },
outlined: { outlined: {
backgroundColor: 'transparent', backgroundColor: 'transparent',
border: '1px solid #e0e0e0', border: '1px solid #333',
}, },
glass: { glass: {
background: 'rgba(255, 255, 255, 0.1)', background: 'rgba(255, 255, 255, 0.05)',
backdropFilter: 'blur(10px)', backdropFilter: 'blur(10px)',
border: '1px solid rgba(255, 255, 255, 0.2)', border: '1px solid rgba(255, 255, 255, 0.1)',
} }
} }
@@ -59,13 +61,13 @@ export function Card({
onMouseEnter={(e) => { onMouseEnter={(e) => {
if (hoverable || onClick) { if (hoverable || onClick) {
e.currentTarget.style.transform = 'translateY(-4px)' e.currentTarget.style.transform = 'translateY(-4px)'
e.currentTarget.style.boxShadow = shadows['2xl'] e.currentTarget.style.boxShadow = shadows.xl
} }
}} }}
onMouseLeave={(e) => { onMouseLeave={(e) => {
if (hoverable || onClick) { if (hoverable || onClick) {
e.currentTarget.style.transform = 'translateY(0)' e.currentTarget.style.transform = 'translateY(0)'
e.currentTarget.style.boxShadow = variant === 'elevated' ? shadows['2xl'] : shadows.md e.currentTarget.style.boxShadow = variant === 'elevated' ? shadows.xl : shadows.md
} }
}} }}
> >

View File

@@ -1,102 +1,95 @@
// BlackRoad Design System Tokens // BlackRoad Official Design System Tokens
// Reference: ~/BLACKROAD_BRAND_SYSTEM.md
export const colors = { export const colors = {
primary: { brand: {
purple: '#667eea', hotPink: '#FF1D6C',
deepPurple: '#764ba2', amber: '#F5A623',
pink: '#f093fb', electricBlue: '#2979FF',
red: '#f5576c' violet: '#9C27B0',
}, },
secondary: { primary: {
cyan: '#4facfe', pink: '#FF1D6C',
lightCyan: '#00f2fe', amber: '#F5A623',
teal: '#a8edea', blue: '#2979FF',
lightPink: '#fed6e3' violet: '#9C27B0',
}, },
neutral: { neutral: {
black: '#0a0a0a', black: '#000000',
darkGray: '#1a1a1a', darkGray: '#111111',
gray: '#2a2a2a', gray: '#1a1a1a',
midGray: '#666', midGray: '#666666',
lightGray: '#888', lightGray: '#999999',
offWhite: '#e0e0e0' silver: '#b0b0b0',
offWhite: '#e0e0e0',
white: '#FFFFFF',
}, },
semantic: { semantic: {
success: '#4ade80', success: '#4ade80',
warning: '#fbbf24', warning: '#F5A623',
error: '#ef4444', error: '#ef4444',
info: '#3b82f6' info: '#2979FF',
} },
} }
export const gradients = { export const gradients = {
primary: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', brand: 'linear-gradient(135deg, #F5A623 0%, #FF1D6C 38.2%, #9C27B0 61.8%, #2979FF 100%)',
secondary: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', pinkToViolet: 'linear-gradient(135deg, #FF1D6C 0%, #9C27B0 100%)',
tertiary: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', amberToPink: 'linear-gradient(135deg, #F5A623 0%, #FF1D6C 100%)',
warm: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)', blueToViolet: 'linear-gradient(135deg, #2979FF 0%, #9C27B0 100%)',
cool: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)',
rainbow: 'linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #4facfe 75%, #00f2fe 100%)'
} }
// Golden Ratio spacing: 8 -> 13 -> 21 -> 34 -> 55 -> 89 -> 144
export const spacing = { export const spacing = {
xs: '0.25rem', xs: '8px',
sm: '0.5rem', sm: '13px',
md: '1rem', md: '21px',
lg: '1.5rem', lg: '34px',
xl: '2rem', xl: '55px',
'2xl': '3rem', '2xl': '89px',
'3xl': '4rem' '3xl': '144px',
} }
export const borderRadius = { export const borderRadius = {
sm: '4px', sm: '4px',
md: '8px', md: '8px',
lg: '12px', lg: '13px',
xl: '16px', xl: '21px',
'2xl': '24px', '2xl': '34px',
full: '9999px' full: '9999px',
} }
export const shadows = { export const shadows = {
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)', sm: '0 1px 2px 0 rgba(0, 0, 0, 0.3)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1)', md: '0 4px 6px -1px rgba(0, 0, 0, 0.4)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1)', lg: '0 10px 15px -3px rgba(0, 0, 0, 0.4)',
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1)', xl: '0 20px 25px -5px rgba(0, 0, 0, 0.4)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)', glow: '0 0 40px rgba(255, 29, 108, 0.2)',
glow: '0 0 40px rgba(102, 126, 234, 0.3)' glowAmber: '0 0 40px rgba(245, 166, 35, 0.2)',
} }
export const transitions = { export const transitions = {
fast: 'all 0.15s ease', fast: 'all 0.15s ease',
normal: 'all 0.2s ease', normal: 'all 0.2s ease',
slow: 'all 0.3s ease' slow: 'all 0.3s ease',
} }
export const typography = { export const typography = {
fontFamily: { fontFamily: {
sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', sans: "'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
mono: '"SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace' mono: "'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace",
}, },
fontSize: { fontSize: {
xs: '0.75rem', xs: '0.75rem',
sm: '0.875rem', sm: '0.85rem',
base: '1rem', base: '1rem',
lg: '1.125rem', lg: '1.1rem',
xl: '1.25rem', xl: '1.25rem',
'2xl': '1.5rem', '2xl': '1.5rem',
'3xl': '1.875rem', '3xl': '2rem',
'4xl': '2.25rem', '4xl': '2.5rem',
'5xl': '3rem', '5xl': '3.25rem',
'6xl': '3.75rem',
'7xl': '4.5rem'
}, },
fontWeight: {
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
extrabold: 800,
black: 900
}
} }
export const breakpoints = { export const breakpoints = {
@@ -104,5 +97,4 @@ export const breakpoints = {
md: '768px', md: '768px',
lg: '1024px', lg: '1024px',
xl: '1280px', xl: '1280px',
'2xl': '1536px'
} }

View File

@@ -1,12 +1,16 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
output: 'standalone', output: 'export',
distDir: 'out',
poweredByHeader: false, poweredByHeader: false,
compress: true,
reactStrictMode: true, reactStrictMode: true,
images: {
unoptimized: true,
},
env: { env: {
SERVICE_NAME: process.env.SERVICE_NAME || 'blackroad-os-infra', SERVICE_NAME: process.env.SERVICE_NAME || 'blackroad-infra',
SERVICE_ENV: process.env.SERVICE_ENV || 'development', SERVICE_ENV: process.env.SERVICE_ENV || 'production',
NEXT_PUBLIC_APP_NAME: process.env.NEXT_PUBLIC_APP_NAME || 'BlackRoad Infrastructure',
}, },
} }

502
dashboard/package-lock.json generated Normal file
View File

@@ -0,0 +1,502 @@
{
"name": "blackroad-os-infra",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "blackroad-os-infra",
"version": "0.0.1",
"dependencies": {
"next": "14.2.15",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^20.17.6",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"typescript": "^5.6.3"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@next/env": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.15.tgz",
"integrity": "sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ==",
"license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz",
"integrity": "sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz",
"integrity": "sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz",
"integrity": "sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz",
"integrity": "sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz",
"integrity": "sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz",
"integrity": "sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz",
"integrity": "sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.15.tgz",
"integrity": "sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz",
"integrity": "sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"license": "Apache-2.0"
},
"node_modules/@swc/helpers": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
"integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
"license": "Apache-2.0",
"dependencies": {
"@swc/counter": "^0.1.3",
"tslib": "^2.4.0"
}
},
"node_modules/@types/node": {
"version": "20.19.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
"integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "18.3.28",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
}
},
"node_modules/@types/react-dom": {
"version": "18.3.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^18.0.0"
}
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001770",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
"integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "CC-BY-4.0"
},
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT"
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/next": {
"version": "14.2.15",
"resolved": "https://registry.npmjs.org/next/-/next-14.2.15.tgz",
"integrity": "sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw==",
"deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.",
"license": "MIT",
"dependencies": {
"@next/env": "14.2.15",
"@swc/helpers": "0.5.5",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
"graceful-fs": "^4.2.11",
"postcss": "8.4.31",
"styled-jsx": "5.1.1"
},
"bin": {
"next": "dist/bin/next"
},
"engines": {
"node": ">=18.17.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "14.2.15",
"@next/swc-darwin-x64": "14.2.15",
"@next/swc-linux-arm64-gnu": "14.2.15",
"@next/swc-linux-arm64-musl": "14.2.15",
"@next/swc-linux-x64-gnu": "14.2.15",
"@next/swc-linux-x64-musl": "14.2.15",
"@next/swc-win32-arm64-msvc": "14.2.15",
"@next/swc-win32-ia32-msvc": "14.2.15",
"@next/swc-win32-x64-msvc": "14.2.15"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
"@playwright/test": "^1.41.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
"@opentelemetry/api": {
"optional": true
},
"@playwright/test": {
"optional": true
},
"sass": {
"optional": true
}
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
},
"peerDependencies": {
"react": "^18.3.1"
}
},
"node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/styled-jsx": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
"integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
"license": "MIT",
"dependencies": {
"client-only": "0.0.1"
},
"engines": {
"node": ">= 12.0.0"
},
"peerDependencies": {
"react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
"optional": true
},
"babel-plugin-macros": {
"optional": true
}
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
}
}
}

View File

@@ -0,0 +1,3 @@
module.exports = {
plugins: {},
}

3
wrangler.toml Normal file
View File

@@ -0,0 +1,3 @@
name = "blackroad-infra"
compatibility_date = "2024-01-01"
pages_build_output_dir = "dashboard/out"