11import { useState } from "react"
2- import { Database , BarChart3 , ToggleLeft , Trophy } from "lucide-react"
2+ import { Database , BarChart3 , Zap , Globe , MessageSquare , Pencil , Plus } from "lucide-react"
33import { LuaCode } from "@/components/ui/lua-code"
44import { cn } from "@/lib/utils"
55
@@ -19,7 +19,7 @@ const products = [
1919 "Power analytics, dashboards, and automations" ,
2020 ] ,
2121 code : `-- Track events from anywhere in your game
22- StackFox.events:track("player_join", {
22+ StackFox.events:track("player_join", {
2323 userId = tostring(player.UserId),
2424 username = player.Name,
2525 region = "us-east",
@@ -63,59 +63,117 @@ StackFox.records:delete("players", playerId)`,
6363 filename : "Records.lua" ,
6464 } ,
6565 {
66- id : "feature-flags " ,
67- name : "Feature Flags " ,
68- tagline : "Ship features safely, control them remotely ." ,
66+ id : "flows " ,
67+ name : "Flows " ,
68+ tagline : "Trigger actions from your events and records ." ,
6969 description :
70- "Enable or disable gameplay features dynamically without pushing a game update. Roll out changes gradually or target specific player groups ." ,
71- Icon : ToggleLeft ,
70+ "React to your game data instantly. When something happens in your game, Flows fires automatically — sending webhooks, posting to Discord, or updating records — without touching your game code ." ,
71+ Icon : Zap ,
7272 status : "soon" as const ,
7373 features : [
74- "Toggle features without game updates " ,
75- "Percentage-based rollouts " ,
76- "Player group and beta tester targeting " ,
77- "Instant kill-switch for live incidents " ,
74+ "Trigger on any event or record update " ,
75+ "Optional conditions to filter when flows run " ,
76+ "Send webhooks, post to Discord, or write records " ,
77+ "Async execution with automatic retries " ,
7878 ] ,
79- code : `local flags = StackFox.flags
80-
81- -- Global flag check
82- if flags:enabled("double_xp_weekend") then
83- xp = xp * 2
84- end
85-
86- -- Targeted rollout
87- if flags:enabledFor("beta_ui", player.UserId) then
88- -- show new inventory UI
89- end` ,
90- filename : "GameLoop.lua" ,
79+ code : null ,
80+ filename : null ,
9181 } ,
92- {
93- id : "leaderboards" ,
94- name : "Leaderboards" ,
95- tagline : "Global and seasonal rankings, fully hosted." ,
96- description :
97- "Manage global and seasonal leaderboards for your game. Real-time rankings, top-N queries, and scheduled resets — all hosted by StackFox." ,
98- Icon : Trophy ,
99- status : "soon" as const ,
100- features : [
101- "Global and per-game leaderboards" ,
102- "Seasonal resets on a configurable schedule" ,
103- "Real-time rank lookups" ,
104- "Paginated top-N queries" ,
105- ] ,
106- code : `local boards = StackFox.leaderboards
82+ ]
10783
108- -- Submit a score at end of match
109- boards:submit("season_1_coins", {
110- playerId = player.UserId,
111- score = totalCoins,
112- })
84+ function FlowsPanel ( ) {
85+ return (
86+ < div className = "border-2 border-foreground shadow-brutal-md overflow-hidden" >
87+ { /* Page header */ }
88+ < div className = "flex items-center justify-between px-4 py-3 border-b border-zinc-200 bg-white" >
89+ < div >
90+ < p className = "text-sm font-bold text-zinc-900" > Flows</ p >
91+ < p className = "text-[11px] text-zinc-500 mt-0.5" > Automate actions from your game data</ p >
92+ </ div >
93+ < button
94+ type = "button"
95+ className = "flex items-center gap-1.5 border border-zinc-200 bg-white px-2.5 py-1.5 text-xs font-medium text-zinc-700"
96+ >
97+ < Plus className = "h-3 w-3" />
98+ New Flow
99+ </ button >
100+ </ div >
113101
114- -- Fetch the top 10 for the UI
115- local top10 = boards:top("season_1_coins", 10)` ,
116- filename : "Leaderboard.lua" ,
117- } ,
118- ]
102+ { /* Section header */ }
103+ < div className = "flex items-center gap-2 px-4 py-2.5 border-b border-zinc-200 bg-zinc-50" >
104+ < Zap className = "h-3.5 w-3.5 text-zinc-400" />
105+ < p className = "text-xs font-semibold uppercase tracking-wider text-zinc-500" > Active Flows</ p >
106+ < span className = "ml-auto text-xs text-zinc-400" > 3 flows</ span >
107+ </ div >
108+
109+ { /* Flow rows */ }
110+ < div className = "divide-y divide-zinc-100 bg-white" >
111+
112+ { /* Flow 1 */ }
113+ < div className = "p-4" >
114+ < div className = "flex items-center gap-2.5 flex-wrap" >
115+ < span className = "border border-primary/30 bg-red-50 px-2 py-0.5 text-[11px] font-bold text-primary shrink-0" >
116+ Event: purchase
117+ </ span >
118+ < span className = "text-sm font-medium text-zinc-800" > High value purchase alert</ span >
119+ < div className = "ml-auto flex items-center gap-3 shrink-0" >
120+ < div className = "flex items-center gap-1.5 text-zinc-400" >
121+ < Globe className = "h-3 w-3" />
122+ < MessageSquare className = "h-3 w-3" />
123+ < Pencil className = "h-3 w-3" />
124+ </ div >
125+ < span className = "flex items-center gap-1 text-[11px] font-medium text-green-600" >
126+ < div className = "w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
127+ Enabled
128+ </ span >
129+ </ div >
130+ </ div >
131+ < div className = "mt-2 flex items-center gap-1.5" >
132+ < span className = "text-[10px] text-zinc-400" > when</ span >
133+ < span className = "border border-zinc-200 bg-zinc-50 px-1.5 py-0.5 font-mono text-[10px] text-zinc-500" >
134+ price > 100
135+ </ span >
136+ </ div >
137+ </ div >
138+
139+ { /* Flow 2 */ }
140+ < div className = "p-4" >
141+ < div className = "flex items-center gap-2.5 flex-wrap" >
142+ < span className = "border border-primary/30 bg-red-50 px-2 py-0.5 text-[11px] font-bold text-primary shrink-0" >
143+ Event: player_join
144+ </ span >
145+ < span className = "text-sm font-medium text-zinc-800" > Discord join log</ span >
146+ < div className = "ml-auto flex items-center gap-3 shrink-0" >
147+ < MessageSquare className = "h-3 w-3 text-zinc-400" />
148+ < span className = "flex items-center gap-1 text-[11px] font-medium text-green-600" >
149+ < div className = "w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
150+ Enabled
151+ </ span >
152+ </ div >
153+ </ div >
154+ </ div >
155+
156+ { /* Flow 3 — disabled */ }
157+ < div className = "p-4" >
158+ < div className = "flex items-center gap-2.5 flex-wrap" >
159+ < span className = "border border-zinc-200 bg-zinc-50 px-2 py-0.5 text-[11px] font-bold text-zinc-400 shrink-0" >
160+ Record: profiles
161+ </ span >
162+ < span className = "text-sm font-medium text-zinc-400" > Weekend XP boost</ span >
163+ < div className = "ml-auto flex items-center gap-3 shrink-0" >
164+ < Pencil className = "h-3 w-3 text-zinc-300" />
165+ < span className = "flex items-center gap-1 text-[11px] font-medium text-zinc-400" >
166+ < div className = "w-1.5 h-1.5 rounded-full bg-zinc-300 shrink-0" />
167+ Disabled
168+ </ span >
169+ </ div >
170+ </ div >
171+ </ div >
172+
173+ </ div >
174+ </ div >
175+ )
176+ }
119177
120178export function ProductsSection ( ) {
121179 const [ activeId , setActiveId ] = useState ( "events" )
@@ -141,7 +199,7 @@ export function ProductsSection() {
141199 key = { p . id }
142200 onClick = { ( ) => setActiveId ( p . id ) }
143201 className = { cn (
144- "flex items-center gap-2.5 px-5 py-4 text-sm font-semibold whitespace-nowrap transition-colors border-r-2 border-zinc-700 last:border-r-0 shrink-0 cursor-pointer" ,
202+ "flex items-center gap-2.5 px-5 py-4 text-sm font-semibold whitespace-nowrap transition-colors border-r-2 border-zinc-700 shrink-0 cursor-pointer" ,
145203 activeId === p . id
146204 ? "bg-white text-zinc-900 border-b-2 border-b-white -mb-px"
147205 : "text-zinc-400 hover:text-white hover:bg-zinc-800" ,
@@ -188,16 +246,20 @@ export function ProductsSection() {
188246 </ ul >
189247 </ div >
190248
191- { /* Right: code example */ }
192- < div className = "border-2 border-foreground bg-zinc-900 shadow-brutal-md" >
193- < div className = "flex items-center gap-2 px-4 py-2.5 border-b border-zinc-700 bg-zinc-800" >
194- < div className = "w-2.5 h-2.5 rounded-full bg-red-500" />
195- < div className = "w-2.5 h-2.5 rounded-full bg-yellow-500" />
196- < div className = "w-2.5 h-2.5 rounded-full bg-green-500" />
197- < span className = "ml-2 text-xs text-zinc-400 font-mono" > { product . filename } </ span >
249+ { /* Right: code example or flows panel */ }
250+ { product . id === "flows" ? (
251+ < FlowsPanel />
252+ ) : (
253+ < div className = "border-2 border-foreground bg-zinc-900 shadow-brutal-md" >
254+ < div className = "flex items-center gap-2 px-4 py-2.5 border-b border-zinc-700 bg-zinc-800" >
255+ < div className = "w-2.5 h-2.5 rounded-full bg-red-500" />
256+ < div className = "w-2.5 h-2.5 rounded-full bg-yellow-500" />
257+ < div className = "w-2.5 h-2.5 rounded-full bg-green-500" />
258+ < span className = "ml-2 text-xs text-zinc-400 font-mono" > { product . filename } </ span >
259+ </ div >
260+ < LuaCode code = { product . code ! } />
198261 </ div >
199- < LuaCode code = { product . code } />
200- </ div >
262+ ) }
201263 </ div >
202264 </ div >
203265 </ div >
0 commit comments