Skip to content

Commit a371ea4

Browse files
committed
cleanup
1 parent c3dbfac commit a371ea4

19 files changed

Lines changed: 192 additions & 193 deletions

File tree

apps/docs/app/api/og/route.tsx

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CSSProperties } from 'react'
12
import { ImageResponse } from 'next/og'
23
import type { NextRequest } from 'next/server'
34

@@ -9,13 +10,47 @@ const TITLE_FONT_SIZE = {
910
small: 48,
1011
} as const
1112
const FONT_CACHE_REVALIDATE_SECONDS = 60 * 60 * 24 * 30
13+
const OG_CONTAINER_STYLE = {
14+
height: '100%',
15+
width: '100%',
16+
display: 'flex',
17+
flexDirection: 'column',
18+
justifyContent: 'space-between',
19+
padding: '56px 64px',
20+
background: '#121212',
21+
fontFamily: 'Geist',
22+
} satisfies CSSProperties
23+
const OG_TITLE_STYLE = {
24+
fontWeight: 500,
25+
color: '#fafafa',
26+
lineHeight: 1.2,
27+
letterSpacing: '-0.02em',
28+
} satisfies CSSProperties
29+
const OG_FOOTER_STYLE = {
30+
display: 'flex',
31+
justifyContent: 'space-between',
32+
alignItems: 'center',
33+
width: '100%',
34+
} satisfies CSSProperties
35+
const OG_DOMAIN_STYLE = {
36+
fontSize: 20,
37+
fontWeight: 400,
38+
color: '#71717a',
39+
} satisfies CSSProperties
1240

1341
function getTitleFontSize(title: string): number {
1442
if (title.length > 45) return TITLE_FONT_SIZE.small
1543
if (title.length > 30) return TITLE_FONT_SIZE.medium
1644
return TITLE_FONT_SIZE.large
1745
}
1846

47+
function getTitleStyle(title: string): CSSProperties {
48+
return {
49+
...OG_TITLE_STYLE,
50+
fontSize: getTitleFontSize(title),
51+
}
52+
}
53+
1954
/**
2055
* Loads a Google Font dynamically by fetching the CSS and extracting the font URL.
2156
*/
@@ -83,50 +118,14 @@ export async function GET(request: NextRequest) {
83118
const fontData = await loadGoogleFont('Geist', '400;500;600', allText)
84119

85120
return new ImageResponse(
86-
<div
87-
style={{
88-
height: '100%',
89-
width: '100%',
90-
display: 'flex',
91-
flexDirection: 'column',
92-
justifyContent: 'space-between',
93-
padding: '56px 64px',
94-
background: '#121212', // Dark mode background matching docs (hsla 0, 0%, 7%)
95-
fontFamily: 'Geist',
96-
}}
97-
>
121+
<div style={OG_CONTAINER_STYLE}>
98122
{/* Title at top */}
99-
<span
100-
style={{
101-
fontSize: getTitleFontSize(title),
102-
fontWeight: 500,
103-
color: '#fafafa', // Light text matching docs
104-
lineHeight: 1.2,
105-
letterSpacing: '-0.02em',
106-
}}
107-
>
108-
{title}
109-
</span>
123+
<span style={getTitleStyle(title)}>{title}</span>
110124

111125
{/* Footer: icon left, domain right */}
112-
<div
113-
style={{
114-
display: 'flex',
115-
justifyContent: 'space-between',
116-
alignItems: 'center',
117-
width: '100%',
118-
}}
119-
>
126+
<div style={OG_FOOTER_STYLE}>
120127
<SimLogoFull />
121-
<span
122-
style={{
123-
fontSize: 20,
124-
fontWeight: 400,
125-
color: '#71717a',
126-
}}
127-
>
128-
docs.sim.ai
129-
</span>
128+
<span style={OG_DOMAIN_STYLE}>docs.sim.ai</span>
130129
</div>
131130
</div>,
132131
{

apps/docs/components/docs-layout/sidebar-components.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { type ReactNode, useEffect, useState } from 'react'
3+
import { type ReactNode, useState } from 'react'
44
import type { Folder, Item, Separator } from 'fumadocs-core/page-tree'
55
import Link from 'next/link'
66
import { usePathname } from 'next/navigation'
@@ -103,12 +103,10 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac
103103
const isApiRef = isApiReferenceFolder(item)
104104
const isOnApiRefPage = stripLangPrefix(pathname).startsWith('/api-reference')
105105
const hasChildren = item.children.length > 0
106-
const [open, setOpen] = useState(hasActiveChild || (isApiRef && isOnApiRefPage))
107-
108-
useEffect(() => {
109-
setOpen(hasActiveChild || (isApiRef && isOnApiRefPage))
110-
}, [hasActiveChild, isApiRef, isOnApiRefPage])
111-
106+
const defaultOpen = hasActiveChild || (isApiRef && isOnApiRefPage)
107+
const [manualOpen, setManualOpen] = useState<{ pathname: string; open: boolean } | null>(null)
108+
const open = manualOpen?.pathname === pathname ? manualOpen.open : defaultOpen
109+
const toggleOpen = () => setManualOpen({ pathname, open: !open })
112110
const active = item.index ? isActive(item.index.url, pathname, false) : false
113111

114112
if (item.index && !hasChildren) {
@@ -152,7 +150,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac
152150
</Link>
153151
{hasChildren && (
154152
<button
155-
onClick={() => setOpen(!open)}
153+
onClick={toggleOpen}
156154
className={cn(
157155
'rounded p-1 hover:bg-fd-accent/50',
158156
'lg:cursor-pointer lg:rounded lg:p-1 lg:transition-colors lg:hover:bg-[#f2f2f2] lg:dark:hover:bg-[#262626]'
@@ -165,7 +163,7 @@ export function SidebarFolder({ item, children }: { item: Folder; children: Reac
165163
</>
166164
) : (
167165
<button
168-
onClick={() => setOpen(!open)}
166+
onClick={toggleOpen}
169167
className={cn(
170168
'flex flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors',
171169
'text-fd-muted-foreground hover:bg-fd-accent/50',

apps/sim/app/(auth)/components/social-login-buttons.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { type ReactNode, useEffect, useState } from 'react'
3+
import { type ReactNode, useState } from 'react'
44
import { Button } from '@/components/emcn'
55
import { GithubIcon, GoogleIcon } from '@/components/icons'
66
import { client } from '@/lib/auth/auth-client'
@@ -22,15 +22,6 @@ export function SocialLoginButtons({
2222
}: SocialLoginButtonsProps) {
2323
const [isGithubLoading, setIsGithubLoading] = useState(false)
2424
const [isGoogleLoading, setIsGoogleLoading] = useState(false)
25-
const [mounted, setMounted] = useState(false)
26-
27-
// Set mounted state to true on client-side
28-
useEffect(() => {
29-
setMounted(true)
30-
}, [])
31-
32-
// Only render on the client side to avoid hydration errors
33-
if (!mounted) return null
3425

3526
async function signInWithGithub() {
3627
if (!githubAvailable) return

apps/sim/app/(landing)/components/navbar/navbar.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const LOGO_CELL = 'flex items-center pl-5 lg:pl-16 pr-5'
4343
const LINK_CELL = 'flex items-center px-3.5'
4444

4545
const emptySubscribe = () => () => {}
46+
const getLocationSearch = () => window.location.search
47+
const getServerLocationSearch = () => ''
4648

4749
interface NavbarProps {
4850
logoOnly?: boolean
@@ -55,10 +57,12 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps
5557
const session = sessionCtx?.data ?? null
5658
const isSessionPending = sessionCtx?.isPending ?? true
5759
const isAuthenticated = Boolean(session?.user?.id)
58-
const [isBrowsingHome, setIsBrowsingHome] = useState(false)
59-
useEffect(() => {
60-
setIsBrowsingHome(new URLSearchParams(window.location.search).has('home'))
61-
}, [])
60+
const locationSearch = useSyncExternalStore(
61+
emptySubscribe,
62+
getLocationSearch,
63+
getServerLocationSearch
64+
)
65+
const isBrowsingHome = new URLSearchParams(locationSearch).has('home')
6266
const useHomeLinks = isAuthenticated || isBrowsingHome
6367
const logoHref = useHomeLinks ? '/?home' : '/'
6468
const mounted = useSyncExternalStore(

apps/sim/app/academy/(catalog)/[courseSlug]/components/course-progress.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
'use client'
22

3-
import { useEffect, useState } from 'react'
3+
import { useMemo, useSyncExternalStore } from 'react'
44
import { CheckCircle2, Circle, ExternalLink, GraduationCap } from 'lucide-react'
55
import Link from 'next/link'
66
import { Loader } from '@/components/emcn'
7-
import { getCompletedLessons } from '@/lib/academy/local-progress'
7+
import {
8+
getCompletedLessonsFromSnapshot,
9+
getCompletedLessonsSnapshot,
10+
getServerCompletedLessonsSnapshot,
11+
subscribeToCompletedLessons,
12+
} from '@/lib/academy/local-progress'
813
import type { Course } from '@/lib/academy/types'
914
import { useSession } from '@/lib/auth/auth-client'
1015
import { useCourseCertificate, useIssueCertificate } from '@/hooks/queries/academy'
@@ -15,11 +20,15 @@ interface CourseProgressProps {
1520
}
1621

1722
export function CourseProgress({ course, courseSlug }: CourseProgressProps) {
18-
// Start with an empty set so SSR and initial client render match, then hydrate from localStorage.
19-
const [completedIds, setCompletedIds] = useState<Set<string>>(() => new Set())
20-
useEffect(() => {
21-
setCompletedIds(getCompletedLessons())
22-
}, [])
23+
const completedIdsSnapshot = useSyncExternalStore(
24+
subscribeToCompletedLessons,
25+
getCompletedLessonsSnapshot,
26+
getServerCompletedLessonsSnapshot
27+
)
28+
const completedIds = useMemo(
29+
() => getCompletedLessonsFromSnapshot(completedIdsSnapshot),
30+
[completedIdsSnapshot]
31+
)
2332
const { data: session } = useSession()
2433
const { data: fetchedCert } = useCourseCertificate(session ? course.id : undefined)
2534
const { mutate: issueCertificate, isPending, data: issuedCert, error } = useIssueCertificate()

apps/sim/app/chat/components/voice-interface/voice-interface.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ export function VoiceInterface({
5757
const [isInitialized, setIsInitialized] = useState(false)
5858
const [isMuted, setIsMuted] = useState(false)
5959
const [audioLevels, setAudioLevels] = useState<number[]>(() => new Array(200).fill(0))
60-
const [permissionStatus, setPermissionStatus] = useState<'prompt' | 'granted' | 'denied'>(
61-
'prompt'
62-
)
60+
const permissionStatusRef = useRef<'prompt' | 'granted' | 'denied'>('prompt')
6361
const [currentTranscript, setCurrentTranscript] = useState('')
6462

6563
const currentStateRef = useRef<'idle' | 'listening' | 'agent_speaking'>('idle')
@@ -251,7 +249,7 @@ export function VoiceInterface({
251249
},
252250
})
253251

254-
setPermissionStatus('granted')
252+
permissionStatusRef.current = 'granted'
255253
mediaStreamRef.current = stream
256254

257255
const ac = new AudioContext({ sampleRate: SAMPLE_RATE })
@@ -300,7 +298,7 @@ export function VoiceInterface({
300298
return true
301299
} catch (error) {
302300
logger.error('Error setting up audio pipeline:', error)
303-
setPermissionStatus('denied')
301+
permissionStatusRef.current = 'denied'
304302
return false
305303
}
306304
}, [])

apps/sim/app/playground/page.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useEffect, useState } from 'react'
3+
import { useState, useSyncExternalStore } from 'react'
44
import { ArrowLeft, Bell, Folder, Key, Moon, Settings, Sun, User } from 'lucide-react'
55
import { notFound, useRouter } from 'next/navigation'
66
import {
@@ -135,6 +135,16 @@ const COMBOBOX_OPTIONS = [
135135
{ label: 'Option 3', value: 'opt3' },
136136
]
137137

138+
const DARK_MODE_EVENT = 'playground:dark-mode-change'
139+
140+
const subscribeToDarkMode = (onStoreChange: () => void) => {
141+
window.addEventListener(DARK_MODE_EVENT, onStoreChange)
142+
return () => window.removeEventListener(DARK_MODE_EVENT, onStoreChange)
143+
}
144+
145+
const getDarkModeSnapshot = () => document.documentElement.classList.contains('dark')
146+
const getServerDarkModeSnapshot = () => false
147+
138148
export default function PlaygroundPage() {
139149
const router = useRouter()
140150
const [comboboxValue, setComboboxValue] = useState('')
@@ -143,7 +153,11 @@ export default function PlaygroundPage() {
143153
const [sliderValue, setSliderValue] = useState([50])
144154
const [timeValue, setTimeValue] = useState('09:30')
145155
const [activeTab, setActiveTab] = useState('profile')
146-
const [isDarkMode, setIsDarkMode] = useState(false)
156+
const isDarkMode = useSyncExternalStore(
157+
subscribeToDarkMode,
158+
getDarkModeSnapshot,
159+
getServerDarkModeSnapshot
160+
)
147161
const [buttonGroupValue, setButtonGroupValue] = useState('curl')
148162
const [dateValue, setDateValue] = useState('')
149163
const [dateRangeStart, setDateRangeStart] = useState('')
@@ -154,14 +168,10 @@ export default function PlaygroundPage() {
154168
])
155169

156170
const toggleDarkMode = () => {
157-
setIsDarkMode(!isDarkMode)
158171
document.documentElement.classList.toggle('dark')
172+
window.dispatchEvent(new Event(DARK_MODE_EVENT))
159173
}
160174

161-
useEffect(() => {
162-
setIsDarkMode(document.documentElement.classList.contains('dark'))
163-
}, [])
164-
165175
if (!isTruthy(env.NEXT_PUBLIC_ENABLE_PLAYGROUND)) {
166176
notFound()
167177
}

0 commit comments

Comments
 (0)