Skip to content

Commit f72ba76

Browse files
committed
looks pretty good
1 parent 23ee248 commit f72ba76

File tree

10 files changed

+185
-38
lines changed

10 files changed

+185
-38
lines changed

apps/desktop2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@hypr/ui": "workspace:^",
2020
"@hypr/utils": "workspace:^",
2121
"@tanstack/react-router": "^1.131.35",
22+
"@tanstack/react-virtual": "^3.13.12",
2223
"@tanstack/zod-adapter": "^1.131.35",
2324
"@tauri-apps/api": "^2",
2425
"@tauri-apps/plugin-opener": "^2",

apps/desktop2/src/components/sidebar.tsx

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,67 @@
11
import { Link } from "@tanstack/react-router";
2+
import { useVirtualizer } from "@tanstack/react-virtual";
3+
import { useRef } from "react";
24
import { useCell, useSortedRowIds } from "tinybase/ui-react";
35

46
import * as hybrid from "../tinybase/store/hybrid";
57

68
export function Sidebar() {
9+
const parentRef = useRef<HTMLDivElement>(null);
10+
711
const sessionIds = useSortedRowIds(
812
"sessions",
913
"createdAt",
1014
true,
11-
0,
12-
10,
15+
undefined,
16+
undefined,
1317
hybrid.STORE_ID,
1418
);
1519

20+
const rowVirtualizer = useVirtualizer({
21+
count: sessionIds?.length ?? 0,
22+
getScrollElement: () => parentRef.current,
23+
estimateSize: () => 72,
24+
});
25+
1626
return (
17-
<div className="sidebar">
18-
<ul>
19-
<li>
20-
{sessionIds?.map((sessionId) => <SessionItem key={sessionId} sessionId={sessionId} />)}
21-
</li>
22-
</ul>
27+
<div
28+
ref={parentRef}
29+
style={{
30+
width: "250px",
31+
height: "100vh",
32+
overflow: "auto",
33+
}}
34+
>
35+
<div
36+
style={{
37+
height: `${rowVirtualizer.getTotalSize()}px`,
38+
width: "100%",
39+
position: "relative",
40+
}}
41+
>
42+
{rowVirtualizer.getVirtualItems().map((virtualItem) => {
43+
const sessionId = sessionIds?.[virtualItem.index];
44+
if (!sessionId) {
45+
return null;
46+
}
47+
48+
return (
49+
<div
50+
key={virtualItem.key}
51+
style={{
52+
position: "absolute",
53+
top: 0,
54+
left: 0,
55+
width: "100%",
56+
height: `${virtualItem.size}px`,
57+
transform: `translateY(${virtualItem.start}px)`,
58+
}}
59+
>
60+
<SessionItem sessionId={sessionId} />
61+
</div>
62+
);
63+
})}
64+
</div>
2365
</div>
2466
);
2567
}
@@ -34,7 +76,7 @@ function SessionItem({ sessionId }: { sessionId: string }) {
3476

3577
return (
3678
<Link to="/app/note/$id" params={{ id: sessionId }}>
37-
<div className="p-4 border border-gray-200">
79+
<div className="w-[200px] p-4 bg-gray-50 border border-gray-200">
3880
<strong>{title}</strong>
3981
</div>
4082
</Link>

apps/desktop2/src/routeTree.gen.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import { Route as AppIndexRouteImport } from './routes/app.index'
1313
import { Route as AppSettingsRouteImport } from './routes/app.settings'
1414
import { Route as AppNoteRouteImport } from './routes/app.note'
1515
import { Route as AppNewRouteImport } from './routes/app.new'
16+
import { Route as AppOrganizationIdRouteImport } from './routes/app.organization.$id'
1617
import { Route as AppNoteIdRouteImport } from './routes/app.note.$id'
18+
import { Route as AppHumanIdRouteImport } from './routes/app.human.$id'
1719

1820
const AppIndexRoute = AppIndexRouteImport.update({
1921
id: '/app/',
@@ -35,33 +37,49 @@ const AppNewRoute = AppNewRouteImport.update({
3537
path: '/app/new',
3638
getParentRoute: () => rootRouteImport,
3739
} as any)
40+
const AppOrganizationIdRoute = AppOrganizationIdRouteImport.update({
41+
id: '/app/organization/$id',
42+
path: '/app/organization/$id',
43+
getParentRoute: () => rootRouteImport,
44+
} as any)
3845
const AppNoteIdRoute = AppNoteIdRouteImport.update({
3946
id: '/$id',
4047
path: '/$id',
4148
getParentRoute: () => AppNoteRoute,
4249
} as any)
50+
const AppHumanIdRoute = AppHumanIdRouteImport.update({
51+
id: '/app/human/$id',
52+
path: '/app/human/$id',
53+
getParentRoute: () => rootRouteImport,
54+
} as any)
4355

4456
export interface FileRoutesByFullPath {
4557
'/app/new': typeof AppNewRoute
4658
'/app/note': typeof AppNoteRouteWithChildren
4759
'/app/settings': typeof AppSettingsRoute
4860
'/app': typeof AppIndexRoute
61+
'/app/human/$id': typeof AppHumanIdRoute
4962
'/app/note/$id': typeof AppNoteIdRoute
63+
'/app/organization/$id': typeof AppOrganizationIdRoute
5064
}
5165
export interface FileRoutesByTo {
5266
'/app/new': typeof AppNewRoute
5367
'/app/note': typeof AppNoteRouteWithChildren
5468
'/app/settings': typeof AppSettingsRoute
5569
'/app': typeof AppIndexRoute
70+
'/app/human/$id': typeof AppHumanIdRoute
5671
'/app/note/$id': typeof AppNoteIdRoute
72+
'/app/organization/$id': typeof AppOrganizationIdRoute
5773
}
5874
export interface FileRoutesById {
5975
__root__: typeof rootRouteImport
6076
'/app/new': typeof AppNewRoute
6177
'/app/note': typeof AppNoteRouteWithChildren
6278
'/app/settings': typeof AppSettingsRoute
6379
'/app/': typeof AppIndexRoute
80+
'/app/human/$id': typeof AppHumanIdRoute
6481
'/app/note/$id': typeof AppNoteIdRoute
82+
'/app/organization/$id': typeof AppOrganizationIdRoute
6583
}
6684
export interface FileRouteTypes {
6785
fileRoutesByFullPath: FileRoutesByFullPath
@@ -70,23 +88,36 @@ export interface FileRouteTypes {
7088
| '/app/note'
7189
| '/app/settings'
7290
| '/app'
91+
| '/app/human/$id'
7392
| '/app/note/$id'
93+
| '/app/organization/$id'
7494
fileRoutesByTo: FileRoutesByTo
75-
to: '/app/new' | '/app/note' | '/app/settings' | '/app' | '/app/note/$id'
95+
to:
96+
| '/app/new'
97+
| '/app/note'
98+
| '/app/settings'
99+
| '/app'
100+
| '/app/human/$id'
101+
| '/app/note/$id'
102+
| '/app/organization/$id'
76103
id:
77104
| '__root__'
78105
| '/app/new'
79106
| '/app/note'
80107
| '/app/settings'
81108
| '/app/'
109+
| '/app/human/$id'
82110
| '/app/note/$id'
111+
| '/app/organization/$id'
83112
fileRoutesById: FileRoutesById
84113
}
85114
export interface RootRouteChildren {
86115
AppNewRoute: typeof AppNewRoute
87116
AppNoteRoute: typeof AppNoteRouteWithChildren
88117
AppSettingsRoute: typeof AppSettingsRoute
89118
AppIndexRoute: typeof AppIndexRoute
119+
AppHumanIdRoute: typeof AppHumanIdRoute
120+
AppOrganizationIdRoute: typeof AppOrganizationIdRoute
90121
}
91122

92123
declare module '@tanstack/react-router' {
@@ -119,13 +150,27 @@ declare module '@tanstack/react-router' {
119150
preLoaderRoute: typeof AppNewRouteImport
120151
parentRoute: typeof rootRouteImport
121152
}
153+
'/app/organization/$id': {
154+
id: '/app/organization/$id'
155+
path: '/app/organization/$id'
156+
fullPath: '/app/organization/$id'
157+
preLoaderRoute: typeof AppOrganizationIdRouteImport
158+
parentRoute: typeof rootRouteImport
159+
}
122160
'/app/note/$id': {
123161
id: '/app/note/$id'
124162
path: '/$id'
125163
fullPath: '/app/note/$id'
126164
preLoaderRoute: typeof AppNoteIdRouteImport
127165
parentRoute: typeof AppNoteRoute
128166
}
167+
'/app/human/$id': {
168+
id: '/app/human/$id'
169+
path: '/app/human/$id'
170+
fullPath: '/app/human/$id'
171+
preLoaderRoute: typeof AppHumanIdRouteImport
172+
parentRoute: typeof rootRouteImport
173+
}
129174
}
130175
}
131176

@@ -145,6 +190,8 @@ const rootRouteChildren: RootRouteChildren = {
145190
AppNoteRoute: AppNoteRouteWithChildren,
146191
AppSettingsRoute: AppSettingsRoute,
147192
AppIndexRoute: AppIndexRoute,
193+
AppHumanIdRoute: AppHumanIdRoute,
194+
AppOrganizationIdRoute: AppOrganizationIdRoute,
148195
}
149196
export const routeTree = rootRouteImport
150197
._addFileChildren(rootRouteChildren)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createFileRoute } from "@tanstack/react-router";
2+
import * as hybrid from "../tinybase/store/hybrid";
3+
export const Route = createFileRoute("/app/human/$id")({
4+
component: Component,
5+
});
6+
7+
function Component() {
8+
const { id } = Route.useParams();
9+
const human = hybrid.UI.useRow("humans", id);
10+
return <pre>{JSON.stringify(human, null, 2)}</pre>;
11+
}

apps/desktop2/src/routes/app.new.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const Route = createFileRoute("/app/new")({
77

88
hybridStore!.setRow("sessions", sessionId, {
99
title: "new",
10-
userId: "1",
10+
humanId: "1",
1111
createdAt: new Date().toISOString(),
1212
});
1313

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { createFileRoute } from "@tanstack/react-router";
2+
import * as hybrid from "../tinybase/store/hybrid";
3+
4+
export const Route = createFileRoute("/app/organization/$id")({
5+
component: Component,
6+
});
7+
8+
function Component() {
9+
const { id } = Route.useParams();
10+
const organization = hybrid.UI.useRow("organizations", id);
11+
return <pre>{JSON.stringify(organization, null, 2)}</pre>;
12+
}
Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
import { createFileRoute } from "@tanstack/react-router";
22

3-
import * as hybrid from "../tinybase/store/hybrid";
4-
53
export const Route = createFileRoute("/app/settings")({
64
component: Component,
75
});
86

97
function Component() {
10-
const row = hybrid.UI.useRow("users", "1", hybrid.STORE_ID);
11-
const store = hybrid.UI.useStore(hybrid.STORE_ID);
12-
13-
const handleModify = () => {
14-
store?.setRow("users", "1", { name: "John2", email: "", createdAt: "" });
15-
};
16-
178
return (
189
<main className="container">
1910
<h1>Settings</h1>
20-
<p>{JSON.stringify(row)}</p>
21-
<button onClick={handleModify}>modify</button>
2211
</main>
2312
);
2413
}

apps/desktop2/src/tinybase/store/hybrid.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ import {
88
} from "tinybase/with-schemas";
99
import { z } from "zod";
1010

11-
import { TABLE_SESSIONS, TABLE_USERS } from "@hypr/db";
11+
import { TABLE_HUMANS, TABLE_ORGANIZATIONS, TABLE_SESSIONS } from "@hypr/db";
1212
import { createCloudPersister } from "../cloudPersister";
1313
import { createLocalPersister } from "../localPersister";
1414
import { createLocalSynchronizer } from "../localSynchronizer";
1515
import { InferTinyBaseSchema } from "../shared";
1616

1717
export const STORE_ID = "hybrid";
1818

19-
export const userSchema = z.object({
19+
export const humanSchema = z.object({
2020
name: z.string(),
2121
email: z.string(),
2222
createdAt: z.string(),
2323
});
2424

25+
export const organizationSchema = z.object({
26+
name: z.string(),
27+
createdAt: z.string(),
28+
});
29+
2530
export const sessionSchema = z.object({
26-
userId: z.string(),
31+
humanId: z.string(),
2732
createdAt: z.string(),
2833
title: z.string(),
2934
raw_md: z.string(),
@@ -33,16 +38,20 @@ export const sessionSchema = z.object({
3338
const TABLE_SCHEMA = {
3439
sessions: {
3540
title: { type: "string" },
36-
userId: { type: "string" },
41+
humanId: { type: "string" },
3742
createdAt: { type: "string" },
3843
raw_md: { type: "string" },
3944
enhanced_md: { type: "string" },
4045
} satisfies InferTinyBaseSchema<typeof sessionSchema>,
41-
users: {
46+
humans: {
4247
name: { type: "string" },
4348
email: { type: "string" },
4449
createdAt: { type: "string" },
45-
} satisfies InferTinyBaseSchema<typeof userSchema>,
50+
} satisfies InferTinyBaseSchema<typeof humanSchema>,
51+
organizations: {
52+
name: { type: "string" },
53+
createdAt: { type: "string" },
54+
} satisfies InferTinyBaseSchema<typeof organizationSchema>,
4655
} as const satisfies TablesSchema;
4756

4857
type Schemas = [typeof TABLE_SCHEMA, NoValuesSchema];
@@ -81,8 +90,12 @@ export const StoreComponent = () => {
8190

8291
return createCloudPersister(store as Store, {
8392
load: {
84-
users: {
85-
tableId: TABLE_USERS,
93+
humans: {
94+
tableId: TABLE_HUMANS,
95+
...shared,
96+
},
97+
organizations: {
98+
tableId: TABLE_ORGANIZATIONS,
8699
...shared,
87100
},
88101
sessions: {
@@ -91,8 +104,12 @@ export const StoreComponent = () => {
91104
},
92105
},
93106
save: {
94-
users: {
95-
tableName: TABLE_USERS,
107+
humans: {
108+
tableName: TABLE_HUMANS,
109+
...shared,
110+
},
111+
organizations: {
112+
tableName: TABLE_ORGANIZATIONS,
96113
...shared,
97114
},
98115
sessions: {
@@ -118,10 +135,10 @@ export const StoreComponent = () => {
118135
store,
119136
(store) =>
120137
createRelationships(store).setRelationshipDefinition(
121-
"sessionUser",
138+
"sessionHuman",
122139
TABLE_SESSIONS,
123-
TABLE_USERS,
124-
"userId",
140+
TABLE_HUMANS,
141+
"humanId",
125142
),
126143
[],
127144
)!;

0 commit comments

Comments
 (0)