summaryrefslogtreecommitdiff
path: root/frontend/src/components/LandingPage.tsx
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-04-28 21:26:11 +0100
committerGitHub <noreply@github.com>2026-04-28 21:26:11 +0100
commit5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be (patch)
treed605f7c02472f67a88f1c71c9258c1bf0823b44a /frontend/src/components/LandingPage.tsx
parentd1fdfb140cc440664f77a24886172f9976a05a31 (diff)
downloadsoryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.tar.gz
soryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.zip
revert PRs #93-#98; enforce strict-linear-DAG + mandatory directive verify (#100)
* revert: roll back PRs #93-#98 to pre-Lexical baseline Reverts the entire chain of directive document UI work and the homepage redesign, restoring the working tree to the state at 3679ceb (before c8b169d / PR #93). PRs reverted: - #93 c8b169d feat: Document UI for directive orchestration with Lexical editor - #94 d6f01a6 fix: compilation error and warnings already merged via PR #93 - #95 5aa3faf fix: resolve compilation error and warnings in Rust backend - #97 d513f93 feat: document UI with contract blocks, expandable logs, and interaction controls - #96 6366941 feat: Redesign homepage with professional PC-98 styling - #98 d1fdfb1 feat: revert broken directive PRs, re-implement Lexical document orchestrator The directive Document UI experiments produced fragile output and merge artifacts; follow-up commits in this PR change orchestration to favor strictly linear DAGs and add goal/conflict verification so future runs do not require this kind of cleanup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(directive): strict-linear-DAG planning + mandatory `directive verify` Tightens directive orchestration so the final PR almost never needs a hand-merge: 1. Planning prompts now strongly bias toward strictly linear DAGs. Parallel steps are reserved for genuinely independent work (e.g. disjoint modules); the default for "in doubt" is sequential. Linear chains inherit each previous step's worktree, so the final merge is typically just a rebase against the base branch. 2. New CLI command `makima directive verify` does a local in-memory `git merge-tree` of HEAD against `<remote>/<base>` and exits non-zero with a list of conflicting files if the PR would not merge cleanly. Pure-local — no API call, no working-tree mutation. 3. Completion / PR-creation prompts now mandate three pre-push checks: a. build (`cargo check` and/or `tsc --noEmit`), b. `makima directive verify --base <base_branch>` must exit 0, and c. an explicit goal-alignment self-check against the diff. The orchestrator is told NOT to push, create the PR, or call `makima directive update` until all three pass. Skipping any of them is documented as a directive failure. The combination means that with a linear DAG the final PR-creation task should almost never see a real conflict — when it does, that is treated as a planning bug to escalate rather than something to paper over with `-X theirs`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(frontend): TS errors pre-existing on master - TaskSlideOutPanel: declare missing `selectedFileDiff` / `selectedFilePath` state hooks that were referenced everywhere but never created, and re-balance the JSX so the `<>...</>` fragment in the non-diff branch is closed (the previous indentation/braces would not parse). - api.ts: add a `getWorktreeDiff` thin wrapper around `getTaskDiff` so TaskDetail's per-file click handler type-checks (the per-file slice is a future improvement; today both return the full task diff). - WorktreeFilesPanel: remove unused `isClickable` local; the gating already reads `onFileClick` directly inline. Run after revert: `npx tsc --noEmit` exits 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'frontend/src/components/LandingPage.tsx')
-rw-r--r--frontend/src/components/LandingPage.tsx262
1 files changed, 169 insertions, 93 deletions
diff --git a/frontend/src/components/LandingPage.tsx b/frontend/src/components/LandingPage.tsx
index e7579b5..f126d6f 100644
--- a/frontend/src/components/LandingPage.tsx
+++ b/frontend/src/components/LandingPage.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect } from 'react'
+import React, { useState, useEffect, useRef } from 'react'
import { LoadingScreen } from './LoadingScreen'
import { HeartLogo } from './HeartLogo'
@@ -9,7 +9,12 @@ interface LandingPageProps {
export function LandingPage({ onLogin }: LandingPageProps) {
const [loading, setLoading] = useState(false)
const [showLanding, setShowLanding] = useState(false)
+ const [isStandby, setIsStandby] = useState(true) // false = LIVE, true = STDBY
+ const [velocity, setVelocity] = useState(0)
+ const [energy, setEnergy] = useState(0)
+ const [ramped, setRamped] = useState(false)
const [pendingAction, setPendingAction] = useState<null | 'makimaRedirect'>(null)
+ const [activePanel, setActivePanel] = useState<null | 'mission' | 'makima'>(null)
// Fade-in landing page content after mount
useEffect(() => {
@@ -17,6 +22,62 @@ export function LandingPage({ onLogin }: LandingPageProps) {
return () => clearTimeout(timer)
}, [])
+ // Ramp up stats, then keep them fluctuating near max
+ useEffect(() => {
+ const VELOCITY_MAX = 603
+ const ENERGY_MAX = 32
+
+ let rampInterval: number | undefined
+ let fluctuateInterval: number | undefined
+
+ // Ramp-up for ~2 seconds
+ const rampDurationMs = 2000
+ const tickMs = 30
+ const vStep = VELOCITY_MAX / (rampDurationMs / tickMs)
+ const eStep = ENERGY_MAX / (rampDurationMs / tickMs)
+
+ rampInterval = window.setInterval(() => {
+ setVelocity((v) => {
+ const next = v + vStep
+ return next >= VELOCITY_MAX ? VELOCITY_MAX : next
+ })
+ setEnergy((e) => {
+ const next = e + eStep
+ return next >= ENERGY_MAX ? ENERGY_MAX : next
+ })
+ }, tickMs)
+
+ const stopRamp = window.setTimeout(() => {
+ if (rampInterval) window.clearInterval(rampInterval)
+ setVelocity(VELOCITY_MAX)
+ setEnergy(ENERGY_MAX)
+ setRamped(true)
+
+ // Fluctuate near the top
+ fluctuateInterval = window.setInterval(() => {
+ setVelocity((v) => {
+ const min = VELOCITY_MAX - 18
+ const max = VELOCITY_MAX
+ const delta = (Math.random() - 0.5) * 6 // ±3
+ const next = Math.max(min, Math.min(max, v + delta))
+ return next
+ })
+ setEnergy((e) => {
+ const min = ENERGY_MAX - 2
+ const max = ENERGY_MAX
+ const delta = (Math.random() - 0.5) * 0.25 // ±0.125
+ const next = Math.max(min, Math.min(max, e + delta))
+ return next
+ })
+ }, 220)
+ }, rampDurationMs + 60)
+
+ return () => {
+ if (rampInterval) window.clearInterval(rampInterval)
+ if (fluctuateInterval) window.clearInterval(fluctuateInterval)
+ }
+ }, [])
+
const handleLoadingComplete = () => {
if (pendingAction === 'makimaRedirect') {
window.location.assign('https://makima.jp')
@@ -30,129 +91,144 @@ export function LandingPage({ onLogin }: LandingPageProps) {
setLoading(true)
}
- const scrollTo = (id: string) => {
- document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' })
+ const handleMission = () => {
+ setActivePanel((mode) => (mode === 'mission' ? null : 'mission'))
+ }
+
+ const handleMakimaPanel = () => {
+ setActivePanel((mode) => (mode === 'makima' ? null : 'makima'))
}
return (
<div>
{loading && <LoadingScreen onComplete={handleLoadingComplete} />}
- {/* Professional floating header */}
{!loading && (
- <div className={`pro-header ${showLanding ? 'fade-in' : 'hidden'}`}>
- <div className="pro-header-content">
- <div className="pro-header-left">
+ <div className={`floating-header ${showLanding ? 'fade-in' : 'hidden'}`}>
+ <div className="header-content">
+ <div className="brand">
<img
src="/logo/crane-logo-transparent.png"
alt="Soryu"
- height={36}
- className="pro-crane-logo"
+ height={40}
+ className="brand-mark"
onError={(e) => {
const img = e.currentTarget as HTMLImageElement
img.onerror = null
img.src = '/logo/crane-logo.png'
}}
/>
- <span className="pro-company-name">SORYU</span>
</div>
-
- <div className="pro-header-center">
+ <div className="header-center">
<HeartLogo size="header-no-rays" className="header-heart" />
</div>
- <nav className="pro-header-nav">
- <button className="pro-nav-link" onClick={() => scrollTo('pro-mission')}>
- Mission
- </button>
- <button className="pro-nav-link" onClick={() => scrollTo('pro-makima')}>
- Makima
- </button>
- <button className="pro-nav-link pro-nav-login" onClick={handleLogin}>
- Login
- </button>
- </nav>
+ <div className="system-info">
+ <div className="info-item">
+ <span className="info-label">System:</span>
+ <span
+ className="info-value live-status clickable"
+ onClick={() => setIsStandby(!isStandby)}
+ title="Click to toggle between LIVE and STANDBY"
+ >
+ <span className={`status-dot ${isStandby ? 'standby' : 'live'}`}></span>
+ {isStandby ? 'STDBY' : 'LIVE'}
+ </span>
+ </div>
+ <div className="info-item">
+ <span className="info-label">Version:</span>
+ <span className="info-value">v1.0.0</span>
+ </div>
+ </div>
</div>
</div>
)}
- {/* Main professional landing layout */}
- <div className={`pro-landing ${showLanding && !loading ? 'fade-in' : 'hidden'}`}>
-
- {/* Hero section */}
- <section className="pro-hero">
- <div className="pro-hero-inner">
- <div className="pro-hero-tagline-jp">そりゅう</div>
- <h1 className="pro-hero-headline">
- Real‑Time Systems for<br />Mission‑Critical Observability
- </h1>
- <p className="pro-hero-sub">
- Low‑latency streaming infrastructure that turns live data into reliable, secure insight.
- </p>
- <div className="pro-hero-cta">
- <button className="pro-btn-primary" onClick={() => scrollTo('pro-mission')}>
- Learn More
- </button>
- <button className="pro-btn-secondary" onClick={handleLogin}>
- <span className="pro-btn-icon">▶</span> Launch Makima
- </button>
- </div>
- </div>
- </section>
-
- {/* Content grid: Mission + Makima cards */}
- <section className="pro-content-grid">
- <div className="pro-card" id="pro-mission">
- <div className="pro-card-header">
- <h2 className="pro-card-title">Mission</h2>
- <div className="pro-card-accent" />
+ <div className={`modern-landing-page manga-style ${showLanding && !loading ? 'fade-in' : 'hidden'}`}>
+ {/* Background GIF fills the main body */}
+ <div className="background-only" aria-hidden="true">
+ <img src="/background-animation.gif" alt="" className="background-gif" />
+ </div>
+
+ {/* Minimal overlay: masthead, issue badge, and CTA */}
+ <div className={`taisho-cover ${activePanel ? 'mission-mode' : ''}`}>
+ <div className="cover-backdrop" aria-hidden="true" />
+ <div className="cover-content">
+ {/* Masthead + Issue badge (kept) */}
+ <div className="masthead">
+ <div className="masthead-vertical">
+ <span className="jp">そりゅう</span>
+ <span className="en">SORYU</span>
+ </div>
+ <div className="issue-badge"><span className="led-heart" aria-hidden="true"></span>かはいい Vol.01</div>
</div>
- <div className="pro-card-body">
- <h3 className="pro-card-subtitle">
- Building real‑time systems for mission-critical observability and surveillance
- </h3>
- <p className="pro-card-text">
- We deliver low‑latency streaming &amp; infrastructure that turns live data into
- reliable, secure insight. Target selection, monitoring and full end to end observability
- to make vital decisions where it matters most.
- </p>
+
+ {/* Hero area becomes Mission content when in mission mode */}
+ {activePanel === 'mission' ? (
+ <div className="mission-screen" role="region" aria-label="Mission">
+ <h1 className="mission-headline">Building real‑time systems for mission-critical observability and surveillance </h1>
+ <img src="/PC98Doukuusei.webp" alt="Mission montage" className="mission-image" />
+ <p className="mission-paragraph">
+ We deliver low‑latency streaming & infrastructure that turns live data into
+ reliable, secure insight. Target selection, monitoring and full end to end observability
+ to make vital decisions where it matters most.
+ </p>
+ </div>
+ ) : activePanel === 'makima' ? (
+ <div className="mission-screen makima-screen" role="region" aria-label="Makima">
+ <h1 className="mission-headline makima-headline">Mesh Orchestration Platform</h1>
+ <span className="makima-badge">Control System</span>
+ <img src="/logo/makima-logo.svg" alt="Makima mesh logo" className="mission-image makima-logo" />
+ <p className="mission-paragraph">
+ Makima is a control system for orchestrating distributed daemon meshes,
+ coordinating concurrent execution across distinct domains.
+ </p>
+ <p className="mission-paragraph">
+ Unified command interface for spawning, monitoring, and directing
+ worker daemons. Real-time task coordination with overlay management.
+ </p>
+ </div>
+ ) : (
+ <div className="hero" />
+ )}
+
+ {/* CTA row spanning full width: left Mission/MAKIMA, right Login */}
+ <div className="cta-area">
+ <div className="cta-left">
+ <button className="taisho-cta" onClick={handleMission}>
+ <span className="cta-text">{activePanel === 'mission' ? 'Close' : 'Mission'}</span>
+ </button>
+ <button className="taisho-cta" onClick={handleMakimaPanel}>
+ <span className="cta-text">{activePanel === 'makima' ? 'Close' : 'MAKIMA'}</span>
+ </button>
+ </div>
+ <div className="cta-right">
+ <button className="taisho-cta" onClick={handleLogin}>
+ <span className="cta-icon">▶</span>
+ <span className="cta-text">Login</span>
+ </button>
+ </div>
</div>
</div>
+ </div>
- <div className="pro-card" id="pro-makima">
- <div className="pro-card-header">
- <h2 className="pro-card-title">Makima</h2>
- <span className="pro-card-badge">Control System</span>
- <div className="pro-card-accent" />
- </div>
- <div className="pro-card-body">
- <img
- src="/logo/makima-logo.svg"
- alt="Makima mesh logo"
- className="pro-makima-logo"
- />
- <h3 className="pro-card-subtitle">Mesh Orchestration Platform</h3>
- <p className="pro-card-text">
- Makima is a control system for orchestrating distributed daemon meshes,
- coordinating concurrent execution across distinct domains.
- </p>
- <p className="pro-card-text">
- Unified command interface for spawning, monitoring, and directing
- worker daemons. Real-time task coordination with overlay management.
- </p>
+ {/* Bottom stats: Velocity + Energy only (hidden in mission mode) */}
+ {!activePanel && (
+ <div className="bottom-stats">
+ <div className="rf-stats">
+ <div className="rf-stat">
+ <span className="label">Velocity</span>
+ <span className="value">{Math.round(velocity)} km/h</span>
+ </div>
+ <div className="rf-stat">
+ <span className="label">Energy</span>
+ <span className="value">{energy.toFixed(1)} MJ</span>
+ </div>
</div>
</div>
- </section>
-
- {/* Footer */}
- <footer className="pro-footer">
- <div className="pro-footer-inner">
- <span className="pro-footer-brand">SORYU</span>
- <span className="pro-footer-sep">—</span>
- <span className="pro-footer-text">Real‑time systems &amp; infrastructure</span>
- </div>
- </footer>
+ )}
</div>
+ {/* MissionDrawer removed in favor of mission screen transformation */}
</div>
)
}