Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/web/app/_components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import Link from "next/link";
import { motion, useReducedMotion } from "motion/react";
import { ease } from "@konjoai/ui";

Expand All @@ -23,12 +24,12 @@ export function Breadcrumbs({ trail }: { trail: Crumb[] }) {
transition={{ duration: 0.3, ease: ease.kanjo, delay: i * 0.07 }}
>
{c.href && !last ? (
<a
<Link
href={c.href}
className="text-konjo-fg-muted transition-colors hover:text-konjo-fg"
>
{c.label}
</a>
</Link>
) : (
<span className={last ? "text-konjo-fg" : undefined}>{c.label}</span>
)}
Expand Down
13 changes: 7 additions & 6 deletions apps/web/app/_components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Link from "next/link";
import { severity as sevColor } from "@konjoai/ui";
import { PRODUCTS } from "@/lib/products";

Expand All @@ -23,7 +24,7 @@ export function Footer() {
</span>
<div className="flex flex-wrap items-center gap-2" aria-label="Product health overview">
{PRODUCTS.map((p) => (
<a
<Link
key={p.slug}
href={`/products/${p.slug}`}
title={`${p.name} — ${p.status}`}
Expand All @@ -35,7 +36,7 @@ export function Footer() {
aria-hidden
/>
{p.slug}
</a>
</Link>
))}
</div>
</div>
Expand All @@ -56,18 +57,18 @@ export function Footer() {
</div>

<nav className="flex flex-wrap items-center gap-x-6 gap-y-2 text-sm">
<a
<Link
href="/#projects"
className="text-konjo-fg-muted transition-colors hover:text-konjo-fg"
>
Products
</a>
<a
</Link>
<Link
href="/status"
className="text-konjo-fg-muted transition-colors hover:text-konjo-fg"
>
Status
</a>
</Link>
<a
href="https://github.com/konjoai"
target="_blank"
Expand Down
5 changes: 3 additions & 2 deletions apps/web/app/_components/LiveTicker.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Link from "next/link";
import { severity as sevColor } from "@konjoai/ui";
import { PRODUCTS } from "@/lib/products";

Expand All @@ -21,7 +22,7 @@ export function LiveTicker() {
? String(p.metric.value)
: p.metric.value.toFixed(1);
return (
<a
<Link
key={`${p.slug}-${i}`}
href={`/products/${p.slug}`}
tabIndex={i >= PRODUCTS.length ? -1 : 0}
Expand All @@ -48,7 +49,7 @@ export function LiveTicker() {
{p.metric.label}
</span>
<span className="ml-4 text-konjo-line/50" aria-hidden>│</span>
</a>
</Link>
);
})}
</div>
Expand Down
111 changes: 111 additions & 0 deletions apps/web/app/_components/PhilosophySection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"use client";

import { motion, useReducedMotion } from "motion/react";
import { ease } from "@konjoai/ui";

const PILLARS = [
{
word: "ቆንጆ",
roman: "Konjo",
lang: "Amharic",
meaning: "Beauty, elegance",
detail: "Craft that earns its complexity. Every surface deliberate, every pixel intentional.",
color: "var(--color-konjo-brand-soft)",
},
{
word: "根性",
roman: "Konjō",
lang: "Japanese",
meaning: "Fighting spirit, grit",
detail: "Ship when it hurts. Refine past good enough. Never stop at the first answer.",
color: "var(--color-konjo-accent)",
},
{
word: "康宙",
roman: "Kāngzhòu",
lang: "Chinese",
meaning: "System health",
detail: "Observability is first-class. Every metric visible. Every failure recoverable.",
color: "var(--color-konjo-good)",
},
{
word: "건조",
roman: "Geonjo",
lang: "Korean",
meaning: "Strip to essence",
detail: "Remove until removal breaks it. Zero ceremony. No dead code. No wasted motion.",
color: "var(--color-konjo-warm)",
},
] as const;

/** Typographic section showcasing the four Konjo values with animated entrance. */
export function PhilosophySection() {
const reduce = useReducedMotion();

return (
<section
className="mx-auto max-w-6xl px-6 pb-24"
aria-label="The Konjo philosophy"
>
<motion.div
initial={reduce ? { opacity: 1 } : { opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-60px" }}
transition={{ duration: 0.55, ease: ease.kanjo }}
className="mb-10"
>
<p className="text-konjo-mono text-xs uppercase tracking-[0.24em] text-konjo-accent">
Four words · one way
</p>
<h2 className="text-konjo-display mt-1 text-3xl font-semibold tracking-tight sm:text-4xl">
The Konjo philosophy
</h2>
<p className="mt-2 max-w-xl text-sm text-konjo-fg-muted">
Each product, each component, each commit — measured against all four.
</p>
</motion.div>

<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{PILLARS.map(({ word, roman, lang, meaning, detail, color }, i) => (
<motion.div
key={roman}
initial={reduce ? { opacity: 1 } : { opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-40px" }}
transition={{ duration: 0.5, ease: ease.kanjo, delay: i * 0.09 }}
whileHover={reduce ? undefined : {
boxShadow: `0 0 0 1px color-mix(in oklch, ${color} 30%, transparent), 0 0 40px -12px color-mix(in oklch, ${color} 20%, transparent)`,
transition: { duration: 0.25 },
}}
className="glass-konjo rounded-konjo-xl p-6"
>
<div className="flex items-start justify-between gap-4">
<span
className="text-konjo-display text-5xl font-semibold leading-none"
style={{ color }}
aria-label={`${word} (${lang})`}
>
{word}
</span>
<span className="text-konjo-mono text-[10px] uppercase tracking-widest text-konjo-fg-faint">
{lang}
</span>
</div>

<div className="mt-4">
<p className="text-konjo-mono text-base font-medium" style={{ color }}>
{roman}
</p>
<p className="text-konjo-display mt-0.5 text-xl font-semibold tracking-tight">
{meaning}
</p>
<p className="mt-3 text-sm leading-relaxed text-konjo-fg-muted">
{detail}
</p>
</div>
</motion.div>
))}
</div>
</section>
);
}
13 changes: 7 additions & 6 deletions apps/web/app/_components/ProjectGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { useRef } from "react";
import Link from "next/link";
import { motion, useMotionValue, useSpring, useReducedMotion } from "motion/react";
import { ease, StatusBadge, severity as sevColor } from "@konjoai/ui";
import { PRODUCTS, type Product } from "@/lib/products";
Expand Down Expand Up @@ -115,14 +116,14 @@ function ProjectCard({ project, index }: { project: Product; index: number }) {

{/* Header: glyph + number + status */}
<div className="flex items-start justify-between gap-4">
<a
<Link
href={`/products/${project.slug}`}
aria-label={`Open ${project.name} product page`}
className="text-konjo-mono text-3xl leading-none transition-colors"
style={{ color: "var(--color-konjo-brand-soft)" }}
>
<span aria-hidden>{project.glyph}</span>
</a>
</Link>
<div className="flex flex-col items-end gap-1.5">
<span className="text-konjo-mono text-[10px] uppercase tracking-widest text-konjo-fg-faint">
{String(index + 1).padStart(2, "0")}
Expand All @@ -132,12 +133,12 @@ function ProjectCard({ project, index }: { project: Product; index: number }) {
</div>

{/* Name + tagline */}
<a
<Link
href={`/products/${project.slug}`}
className="text-konjo-display mt-5 inline-block text-2xl font-semibold tracking-tight transition-colors hover:text-konjo-violet"
>
{project.name}
</a>
</Link>
<p className="mt-2 text-sm leading-relaxed text-konjo-fg-muted">
{project.tagline}
</p>
Expand All @@ -161,13 +162,13 @@ function ProjectCard({ project, index }: { project: Product; index: number }) {

{/* CTAs */}
<div className="mt-5 flex items-center gap-3 text-xs">
<a
<Link
href={`/products/${project.slug}`}
className="text-konjo-mono inline-flex items-center gap-1.5 rounded-konjo border border-konjo-line bg-konjo-surface-2/60 px-3 py-1.5 text-konjo-fg transition-colors hover:bg-konjo-surface-2"
>
Details
<span aria-hidden>→</span>
</a>
</Link>
<a
href={project.github}
target="_blank"
Expand Down
60 changes: 60 additions & 0 deletions apps/web/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Link from "next/link";
import { Footer } from "./_components/Footer";

/** Konjo-branded 404 page — minimal, beautiful, on-brand. */
export default function NotFound() {
return (
<main className="aurora-konjo relative flex min-h-screen flex-col items-center justify-center overflow-x-clip px-6 text-center">
<div className="aurora-konjo-bg" aria-hidden />

<div className="relative">
<p className="text-konjo-mono mb-4 text-xs uppercase tracking-[0.3em] text-konjo-fg-faint">
Error 404
</p>

<h1
className="text-konjo-display text-[7rem] font-semibold leading-none tracking-tight sm:text-[10rem]"
style={{
background:
"linear-gradient(120deg, var(--color-konjo-brand-soft) 0%, var(--color-konjo-brand) 40%, var(--color-konjo-accent) 100%)",
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
color: "transparent",
}}
>
404
</h1>

<p className="mt-4 text-balance text-lg text-konjo-fg-muted">
This page wandered out of the constellation.
</p>

<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
<Link
href="/"
className="rounded-konjo-lg px-6 py-3 text-sm font-medium text-white transition-transform hover:-translate-y-0.5"
style={{ background: "var(--color-konjo-brand)" }}
>
Back to home
</Link>
<Link
href="/#projects"
className="rounded-konjo-lg border border-konjo-line bg-konjo-surface/60 px-6 py-3 text-sm font-medium text-konjo-fg backdrop-blur transition-colors hover:bg-konjo-surface"
>
Browse products
</Link>
</div>

<div
aria-hidden
className="text-konjo-mono pointer-events-none absolute -right-16 -top-16 select-none text-[200px] font-semibold leading-none text-konjo-violet/5 sm:-right-24 sm:-top-20 sm:text-[280px]"
>
</div>
</div>

<Footer />
</main>
);
}
2 changes: 2 additions & 0 deletions apps/web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ProjectGrid } from "./_components/ProjectGrid";
import { Hero } from "./_components/Hero";
import { LiveTicker } from "./_components/LiveTicker";
import { ConstellationMap } from "./_components/ConstellationMap";
import { PhilosophySection } from "./_components/PhilosophySection";
import { DesignPreview } from "./_components/DesignPreview";
import { Footer } from "./_components/Footer";

Expand All @@ -12,6 +13,7 @@ export default function HomePage() {
<Hero />
<LiveTicker />
<ConstellationMap />
<PhilosophySection />
<DesignPreview />
<ProjectGrid />
<Footer />
Expand Down
62 changes: 62 additions & 0 deletions apps/web/app/products/[slug]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/** Skeleton loader shown while the product page server component streams in. */
export default function ProductLoading() {
return (
<main className="aurora-konjo relative min-h-screen overflow-x-clip">
<div className="aurora-konjo-bg" aria-hidden />

{/* Breadcrumb skeleton */}
<div className="mx-auto max-w-6xl px-6 pt-6">
<div className="flex items-center gap-2">
<div className="h-3 w-12 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-3 w-2 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-3 w-16 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-3 w-2 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-3 w-20 animate-pulse rounded-konjo bg-konjo-surface-2" />
</div>
</div>

{/* Metric strip skeleton */}
<div className="mx-auto max-w-6xl border-b border-konjo-line/40 px-6 py-5">
<div className="flex items-baseline gap-3">
<div className="h-14 w-28 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-3 w-20 animate-pulse rounded-konjo bg-konjo-surface-2" />
</div>
</div>

{/* Hero skeleton */}
<div className="relative mx-auto max-w-6xl px-6 pt-24 pb-12 sm:pt-32">
<div className="mb-3 h-3 w-40 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="mb-4 h-16 w-72 animate-pulse rounded-konjo bg-konjo-surface-2 sm:w-96" />
<div className="mb-2 h-5 w-full max-w-lg animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="mb-5 h-5 w-2/3 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="flex gap-3">
<div className="h-10 w-36 animate-pulse rounded-konjo-lg bg-konjo-surface-2" />
<div className="h-10 w-28 animate-pulse rounded-konjo-lg bg-konjo-surface-2" />
</div>
</div>

{/* About skeleton */}
<div className="mx-auto max-w-6xl px-6 pb-12">
<div className="space-y-3">
<div className="h-5 w-full max-w-2xl animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-5 w-5/6 max-w-2xl animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="h-5 w-4/6 max-w-2xl animate-pulse rounded-konjo bg-konjo-surface-2" />
</div>
</div>

{/* Feature grid skeleton */}
<div className="mx-auto max-w-6xl px-6 pb-16">
<div className="mb-6 h-8 w-40 animate-pulse rounded-konjo bg-konjo-surface-2" />
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{Array.from({ length: 3 }, (_, i) => (
<div
key={i}
className="glass-konjo rounded-konjo-lg h-40 animate-pulse"
style={{ animationDelay: `${i * 100}ms` }}
/>
))}
</div>
</div>
</main>
);
}
Loading
Loading