@@ -16,7 +16,7 @@ function Logo({ size = 32 }: { size?: number }) {
1616}
1717
1818// ─── Rings mockup ─────────────────────────────────────────────────────────────
19- function RingsMockup ( { sessionPct, weeklyPct } : { sessionPct : number ; weeklyPct : number } ) {
19+ function RingsMockup ( { sessionPct, weeklyPct, resetTime } : { sessionPct : number ; weeklyPct : number ; resetTime : string } ) {
2020 const r1 = 70 ; const r2 = 46 ; const cx = 100 ; const cy = 100
2121 const c1 = 2 * Math . PI * r1 ; const c2 = 2 * Math . PI * r2
2222 const [ visible , setVisible ] = useState ( false )
@@ -42,6 +42,7 @@ function RingsMockup({ sessionPct, weeklyPct }: { sessionPct: number; weeklyPct:
4242 strokeDasharray = { `${ ( visible ? sessionPct : 0 ) * c2 } ${ c2 } ` }
4343 transform = { `rotate(-90 ${ cx } ${ cy } )` }
4444 style = { { transition : 'stroke-dasharray 1.2s cubic-bezier(0.4,0,0.2,1) 0.15s' } } />
45+ < text x = { cx } y = { cy + 5 } textAnchor = "middle" fontFamily = { MONO } fontSize = "14" fontWeight = "700" fill = { INK } letterSpacing = "-0.02em" > { resetTime } </ text >
4546 </ svg >
4647 )
4748}
@@ -144,22 +145,34 @@ function Nav() {
144145}
145146
146147// ─── Hero ────────────────────────────────────────────────────────────────────
148+ function randomTime ( ) {
149+ const h = Math . floor ( Math . random ( ) * 5 )
150+ const m = Math . floor ( Math . random ( ) * 60 )
151+ return h > 0 ? `${ h } h${ m > 0 ? `${ m } m` : '' } ` : `${ m } m`
152+ }
147153function Hero ( ) {
154+ const [ s , setS ] = useState ( 0.67 )
155+ const [ w , setW ] = useState ( 0.42 )
156+ const [ t , setT ] = useState ( '1h30m' )
157+ const [ s2 , setS2 ] = useState ( 0.31 )
158+ const [ w2 , setW2 ] = useState ( 0.78 )
159+ const [ t2 , setT2 ] = useState ( '3h05m' )
160+ const randomize = ( ) => {
161+ setS ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) ; setW ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) ; setT ( randomTime ( ) )
162+ setS2 ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) ; setW2 ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) ; setT2 ( randomTime ( ) )
163+ }
164+ useEffect ( ( ) => { const id = setInterval ( randomize , 2000 ) ; return ( ) => clearInterval ( id ) } , [ ] )
148165 return (
149166 < section id = "hero" style = { { borderBottom : `2px solid ${ INK } ` } } >
150167 < div style = { { maxWidth : 1200 , margin : '0 auto' , padding : '0 24px' } } >
151- < div style = { { display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' , padding : '14px 0' , borderBottom : `1px solid rgba(10,10,10,0.18)` , fontFamily : MONO , fontSize : 11 , letterSpacing : '0.1em' , textTransform : 'uppercase' , color : MUTED } } >
152- < span > [ REV 1.0 ]</ span >
153- < span > macOS 14+ // Apple Silicon + Intel</ span >
154- </ div >
155168
156169 < div className = "hero-grid" >
157170 < div className = "hero-text" >
158171 < p style = { { fontFamily : MONO , fontSize : 11 , fontWeight : 700 , letterSpacing : '0.15em' , textTransform : 'uppercase' , color : PRIMARY , marginBottom : 18 } } >
159172 /// FREE & OPEN SOURCE MACOS APP
160173 </ p >
161174 < h1 style = { { fontFamily : DISPLAY , fontSize : 'clamp(56px, 9vw, 116px)' , lineHeight : 0.88 , letterSpacing : '-0.04em' , textTransform : 'uppercase' , color : INK , marginBottom : 32 } } >
162- KNOW < br /> YOUR < br /> LIMITS.
175+ CLAUDE < br /> USAGE < br /> < span style = { { color : PRIMARY } } > MONITOR </ span >
163176 </ h1 >
164177 < p style = { { fontFamily : MONO , fontSize : 14 , lineHeight : 1.75 , color : '#3A3A3A' , maxWidth : 460 , marginBottom : 40 } } >
165178 Monitor Claude session & weekly usage across < strong > multiple accounts</ strong > from your macOS menu bar. Two rings. Always visible. Never surprised by a rate limit again.
@@ -177,43 +190,7 @@ function Hero() {
177190 </ p >
178191 </ div >
179192
180- < div className = "hero-logo-box" style = { { border : `2px solid ${ INK } ` , width : 200 , height : 200 , display : 'flex' , alignItems : 'center' , justifyContent : 'center' , flexShrink : 0 , justifySelf : 'end' } } >
181- < Logo size = { 144 } />
182- </ div >
183- </ div >
184- </ div >
185- </ section >
186- )
187- }
188-
189- // ─── App Mockup ───────────────────────────────────────────────────────────────
190- function AppMockup ( ) {
191- const [ s , setS ] = useState ( 0.67 )
192- const [ w , setW ] = useState ( 0.42 )
193- const randomize = ( ) => { setS ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) ; setW ( + ( Math . random ( ) * 0.88 + 0.06 ) . toFixed ( 2 ) ) }
194-
195- return (
196- < section id = "mockup" style = { { borderBottom : `2px solid ${ INK } ` , padding : '72px 24px' } } >
197- < div style = { { maxWidth : 1200 , margin : '0 auto' } } >
198- < div className = "grid-2col" style = { { border : `2px solid ${ INK } ` } } >
199- < div className = "mockup-left" style = { { borderRight : `2px solid ${ INK } ` , padding : '48px' , display : 'flex' , flexDirection : 'column' , justifyContent : 'space-between' } } >
200- < div >
201- < p style = { { fontFamily : MONO , fontSize : 11 , fontWeight : 700 , letterSpacing : '0.15em' , textTransform : 'uppercase' , color : PRIMARY , marginBottom : 16 } } >
202- [ APP PREVIEW ]
203- </ p >
204- < h2 style = { { fontFamily : DISPLAY , fontSize : 'clamp(30px, 4vw, 52px)' , lineHeight : 0.93 , letterSpacing : '-0.03em' , textTransform : 'uppercase' , color : INK , marginBottom : 24 } } >
205- TWO RINGS.< br /> ALL THE< br /> CONTEXT.
206- </ h2 >
207- < p style = { { fontFamily : MONO , fontSize : 12 , lineHeight : 1.75 , color : '#3A3A3A' , maxWidth : 320 } } >
208- Outer ring = weekly limit. Inner ring = current session. Reset time shown inline. No reading required.
209- </ p >
210- </ div >
211- < button onClick = { randomize } className = "btn-ghost" style = { { padding : '10px 20px' , fontSize : 11 , marginTop : 32 , alignSelf : 'flex-start' , cursor : 'pointer' } } >
212- Randomize data →
213- </ button >
214- </ div >
215-
216- < div style = { { padding : 48 , display : 'flex' , alignItems : 'center' , justifyContent : 'center' } } >
193+ < div className = "hero-logo-box" style = { { justifySelf : 'end' , flexShrink : 0 } } >
217194 < div style = { { border : `2px solid ${ INK } ` , background : '#fff' , width : '100%' , maxWidth : 340 } } >
218195 < div style = { { borderBottom : `2px solid ${ INK } ` , padding : '9px 16px' , display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' } } >
219196 < span style = { { fontFamily : MONO , fontSize : 10 , fontWeight : 700 , letterSpacing : '0.08em' , textTransform : 'uppercase' } } > Claude Usage Monitor</ span >
@@ -224,19 +201,34 @@ function AppMockup() {
224201 < span style = { { width : 8 , height : 8 , background : '#22c55e' , border : '1px solid rgba(10,10,10,0.3)' , display : 'inline-block' } } />
225202 </ div >
226203 < div style = { { padding : '20px 16px' , display : 'flex' , gap : 16 , alignItems : 'center' } } >
227- < RingsMockup sessionPct = { s } weeklyPct = { w } />
204+ < RingsMockup sessionPct = { s } weeklyPct = { w } resetTime = { t } />
228205 < div style = { { flex : 1 , minWidth : 0 } } >
229206 < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , letterSpacing : '0.08em' , textTransform : 'uppercase' , marginBottom : 3 } } > Session</ p >
230207 < p style = { { fontFamily : DISPLAY , fontSize : 30 , color : INK , lineHeight : 1 , marginBottom : 3 } } > { Math . round ( s * 100 ) } %</ p >
231- < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , marginBottom : 14 } } > Resets in 2h 14m </ p >
208+ < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , marginBottom : 14 } } > Resets in { t } </ p >
232209 < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , letterSpacing : '0.08em' , textTransform : 'uppercase' , marginBottom : 3 } } > Weekly</ p >
233210 < p style = { { fontFamily : DISPLAY , fontSize : 30 , color : PRIMARY , lineHeight : 1 , marginBottom : 3 } } > { Math . round ( w * 100 ) } %</ p >
234211 < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED } } > Resets Mon 9:00 AM</ p >
235212 </ div >
236213 </ div >
214+ < div style = { { borderTop : '1px solid rgba(10,10,10,0.12)' , borderBottom : '1px solid rgba(10,10,10,0.12)' , padding : '8px 16px' , display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' } } >
215+ < span style = { { fontFamily : MONO , fontSize : 11 , fontWeight : 700 } } > Work</ span >
216+ < span style = { { width : 8 , height : 8 , background : '#22c55e' , border : '1px solid rgba(10,10,10,0.3)' , display : 'inline-block' } } />
217+ </ div >
218+ < div style = { { padding : '20px 16px' , display : 'flex' , gap : 16 , alignItems : 'center' } } >
219+ < RingsMockup sessionPct = { s2 } weeklyPct = { w2 } resetTime = { t2 } />
220+ < div style = { { flex : 1 , minWidth : 0 } } >
221+ < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , letterSpacing : '0.08em' , textTransform : 'uppercase' , marginBottom : 3 } } > Session</ p >
222+ < p style = { { fontFamily : DISPLAY , fontSize : 30 , color : INK , lineHeight : 1 , marginBottom : 3 } } > { Math . round ( s2 * 100 ) } %</ p >
223+ < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , marginBottom : 14 } } > Resets in { t2 } </ p >
224+ < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED , letterSpacing : '0.08em' , textTransform : 'uppercase' , marginBottom : 3 } } > Weekly</ p >
225+ < p style = { { fontFamily : DISPLAY , fontSize : 30 , color : PRIMARY , lineHeight : 1 , marginBottom : 3 } } > { Math . round ( w2 * 100 ) } %</ p >
226+ < p style = { { fontFamily : MONO , fontSize : 9 , color : MUTED } } > Resets Mon 9:00 AM</ p >
227+ </ div >
228+ </ div >
237229 < div style = { { borderTop : '1px solid rgba(10,10,10,0.12)' , padding : '8px 16px' , display : 'flex' , justifyContent : 'space-between' } } >
238230 < span style = { { fontFamily : MONO , fontSize : 9 , color : MUTED } } > Updated just now</ span >
239- < span style = { { fontFamily : MONO , fontSize : 9 , color : MUTED } } > github.com/phucbm </ span >
231+ < button onClick = { randomize } style = { { fontFamily : MONO , fontSize : 9 , color : PRIMARY , background : 'none' , border : 'none' , cursor : 'pointer' , padding : 0 , letterSpacing : '0.06em' } } > Randomize → </ button >
240232 </ div >
241233 </ div >
242234 </ div >
@@ -390,7 +382,6 @@ export default function App() {
390382 < Nav />
391383 < Hero />
392384 < Ticker />
393- < AppMockup />
394385 < Features />
395386 < HowItWorks />
396387 < FAQ />
0 commit comments