mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-02 22:32:27 +08:00
fix: fix hydration mismatch for DrawIO theme loading (#131)
- Load DrawIO theme from localStorage after mount with useEffect - Add loading spinner while theme loads - Prevents SSR/client hydration mismatch (server has no localStorage) Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
This commit is contained in:
60
app/page.tsx
60
app/page.tsx
@@ -15,20 +15,26 @@ export default function Home() {
|
|||||||
const { drawioRef, handleDiagramExport } = useDiagram()
|
const { drawioRef, handleDiagramExport } = useDiagram()
|
||||||
const [isMobile, setIsMobile] = useState(false)
|
const [isMobile, setIsMobile] = useState(false)
|
||||||
const [isChatVisible, setIsChatVisible] = useState(true)
|
const [isChatVisible, setIsChatVisible] = useState(true)
|
||||||
const [drawioUi, setDrawioUi] = useState<"min" | "sketch">(() => {
|
const [drawioUi, setDrawioUi] = useState<"min" | "sketch">("min")
|
||||||
if (typeof window !== "undefined") {
|
const [isThemeLoaded, setIsThemeLoaded] = useState(false)
|
||||||
const saved = localStorage.getItem("drawio-theme")
|
|
||||||
if (saved === "min" || saved === "sketch") return saved
|
// Load theme from localStorage after mount to avoid hydration mismatch
|
||||||
|
useEffect(() => {
|
||||||
|
const saved = localStorage.getItem("drawio-theme")
|
||||||
|
if (saved === "min" || saved === "sketch") {
|
||||||
|
setDrawioUi(saved)
|
||||||
}
|
}
|
||||||
return "min"
|
setIsThemeLoaded(true)
|
||||||
})
|
}, [])
|
||||||
const [closeProtection, setCloseProtection] = useState(() => {
|
const [closeProtection, setCloseProtection] = useState(true)
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
const saved = localStorage.getItem(STORAGE_CLOSE_PROTECTION_KEY)
|
// Load close protection setting from localStorage after mount
|
||||||
return saved !== "false" // Default to true
|
useEffect(() => {
|
||||||
|
const saved = localStorage.getItem(STORAGE_CLOSE_PROTECTION_KEY)
|
||||||
|
if (saved === "false") {
|
||||||
|
setCloseProtection(false)
|
||||||
}
|
}
|
||||||
return true
|
}, [])
|
||||||
})
|
|
||||||
const chatPanelRef = useRef<ImperativePanelHandle>(null)
|
const chatPanelRef = useRef<ImperativePanelHandle>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -96,18 +102,24 @@ export default function Home() {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
|
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
|
||||||
<DrawIoEmbed
|
{isThemeLoaded ? (
|
||||||
key={drawioUi}
|
<DrawIoEmbed
|
||||||
ref={drawioRef}
|
key={drawioUi}
|
||||||
onExport={handleDiagramExport}
|
ref={drawioRef}
|
||||||
urlParameters={{
|
onExport={handleDiagramExport}
|
||||||
ui: drawioUi,
|
urlParameters={{
|
||||||
spin: true,
|
ui: drawioUi,
|
||||||
libraries: false,
|
spin: true,
|
||||||
saveAndExit: false,
|
libraries: false,
|
||||||
noExitBtn: true,
|
saveAndExit: false,
|
||||||
}}
|
noExitBtn: true,
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="h-full w-full flex items-center justify-center">
|
||||||
|
<div className="animate-spin h-8 w-8 border-4 border-primary border-t-transparent rounded-full" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
|
|||||||
Reference in New Issue
Block a user