Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions examples/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {Metadata} from 'next';
import {Geist, Geist_Mono} from 'next/font/google';
import {NavBar} from '@/components/nav/NavBar';
import {ThemeProvider} from '@/components/nav/ThemeProvider';
import {StoreHydrator} from '@/components/shared/StoreHydrator';
import './globals.css';

const geistSans = Geist({
Expand All @@ -26,15 +27,17 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning={true}>
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<ThemeProvider />
<NavBar />
<main className="mx-auto max-w-6xl px-4 sm:px-6 py-8 pb-16">
{children}
</main>
<StoreHydrator>
<ThemeProvider />
<NavBar />
<main className="mx-auto max-w-6xl px-4 sm:px-6 py-8 pb-16">
{children}
</main>
</StoreHydrator>
</body>
</html>
);
Expand Down
3 changes: 1 addition & 2 deletions examples/nextjs/src/app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {PersistControls} from '@/components/settings/PersistControls';
import {SettingsForm} from '@/components/settings/SettingsForm';
import {StorageDebugPanel} from '@/components/settings/StorageDebugPanel';

export default function SettingsPage() {
return (
Expand All @@ -23,7 +22,7 @@ export default function SettingsPage() {
<SettingsForm />
<div className="space-y-6">
<PersistControls />
<StorageDebugPanel />
{/*<StorageDebugPanel />*/}
</div>
</div>
</div>
Expand Down
24 changes: 11 additions & 13 deletions examples/nextjs/src/components/settings/SettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@ import {ApiInfo} from '@/components/shared/ApiInfo';
import {settingsStore} from '@/stores/settings-store';

export function SettingsForm() {
const snap = useStore(settingsStore);
const store = useStore(settingsStore);

return (
<div className="bg-card border border-border rounded-lg p-4 space-y-4">
<h2 className="font-semibold">Preferences</h2>
<ApiInfo
apis={['createClassyStore (plain object)', 'useStore (auto-tracked)']}
description="Plain object store (not a class). Direct property mutation — no setter methods needed."
code={`const settingsStore = createClassyStore({
theme: 'system',
fontSize: 16,
compactMode: false,
});
code={`const settingsStore = create);
// mutation: settingsStore.theme = 'dark';`}
/>
<p className="text-xs text-muted">
Expand All @@ -28,7 +24,7 @@ export function SettingsForm() {
<span className="text-muted text-xs">Theme</span>
<select
className="border border-border bg-background rounded px-3 py-1.5 text-sm"
value={snap.theme}
value={store.theme}
onChange={(e) => {
settingsStore.theme = e.target.value as 'light' | 'dark' | 'system';
}}
Expand All @@ -40,12 +36,14 @@ export function SettingsForm() {
</label>

<label className="flex flex-col gap-1 text-sm">
<span className="text-muted text-xs">Font Size: {snap.fontSize}px</span>
<span className="text-muted text-xs">
Font Size: {store.fontSize}px
</span>
<input
type="range"
min={12}
max={24}
value={snap.fontSize}
value={store.fontSize}
onChange={(e) => {
settingsStore.fontSize = Number(e.target.value);
}}
Expand All @@ -56,7 +54,7 @@ export function SettingsForm() {
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={snap.compactMode}
checked={store.compactMode}
onChange={() => {
settingsStore.compactMode = !settingsStore.compactMode;
}}
Expand All @@ -68,7 +66,7 @@ export function SettingsForm() {
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={snap.notifications}
checked={store.notifications}
onChange={() => {
settingsStore.notifications = !settingsStore.notifications;
}}
Expand All @@ -82,7 +80,7 @@ export function SettingsForm() {
<input
type="number"
className="border border-border bg-background rounded px-3 py-1.5 text-sm w-24"
value={snap.defaultServings}
value={store.defaultServings}
onChange={(e) => {
settingsStore.defaultServings = Number(e.target.value) || 1;
}}
Expand All @@ -93,7 +91,7 @@ export function SettingsForm() {
<span className="text-muted text-xs">Measurement Unit</span>
<select
className="border border-border bg-background rounded px-3 py-1.5 text-sm"
value={snap.measurementUnit}
value={store.measurementUnit}
onChange={(e) => {
settingsStore.measurementUnit = e.target.value as
| 'metric'
Expand Down
23 changes: 23 additions & 0 deletions examples/nextjs/src/components/shared/StoreHydrator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import {type ReactNode, useEffect, useState} from 'react';
import {settingsPersist} from '@/stores/settings-store';
import {shoppingPersist} from '@/stores/shopping-store';

const persists = [settingsPersist, shoppingPersist];

export function StoreHydrator({children}: {children: ReactNode}) {
const [hydrated, setHydrated] = useState(false);

useEffect(() => {
Promise.all(persists.map((p) => p.rehydrate())).then(() =>
setHydrated(true),
);
}, []);

if (!hydrated) {
return null;
}

return <>{children}</>;
}
1 change: 0 additions & 1 deletion examples/nextjs/src/stores/planner-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ export const plannerPersist = persist(plannerStore, {
return state;
},
merge: 'shallow',
skipHydration: true,
syncTabs: true,
expireIn: 7 * 24 * 60 * 60 * 1000,
clearOnExpire: true,
Expand Down
18 changes: 10 additions & 8 deletions examples/nextjs/src/stores/settings-store.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import {createClassyStore} from '@codebelt/classy-store';
import {devtools, persist} from '@codebelt/classy-store/utils';

export const settingsStore = createClassyStore({
theme: 'system' as 'light' | 'dark' | 'system',
fontSize: 16,
compactMode: false,
notifications: true,
defaultServings: 4,
measurementUnit: 'metric' as 'metric' | 'imperial',
});
class SettingsStore {
theme = 'system' as 'light' | 'dark' | 'system';
fontSize = 16;
compactMode = false;
notifications = true;
defaultServings = 4;
measurementUnit = 'metric' as 'metric' | 'imperial';
}

export const settingsStore = createClassyStore(new SettingsStore());

export const settingsPersist = persist(settingsStore, {
name: 'classy-kitchen-settings',
Expand Down
Loading