Skip to content

Commit 9a07062

Browse files
authored
docs: setup components type in studio (#1072)
1 parent 119e1d0 commit 9a07062

File tree

16 files changed

+1365
-78
lines changed

16 files changed

+1365
-78
lines changed

apps/docs/app/lib/sanity.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { type QueryParams, createClient } from '@sanity/client';
2+
3+
export const client = createClient({
4+
projectId: 'tq6w17ny',
5+
dataset: 'grunnmuren',
6+
apiVersion: '2024-09-18',
7+
useCdn: true,
8+
});
9+
10+
export async function sanityFetch<const QueryString extends string>({
11+
query,
12+
params = {},
13+
}: {
14+
query: QueryString;
15+
params?: QueryParams;
16+
}) {
17+
// Not sure what's happening here, but I need to set filterReponse to false to get the data as an array?
18+
const { result } = await client.fetch(query, params, {
19+
filterResponse: false,
20+
});
21+
22+
return { data: result };
23+
}

apps/docs/app/routeTree.gen.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,15 @@
1111
// Import Routes
1212

1313
import { Route as rootRoute } from './routes/__root'
14-
import { Route as StudioImport } from './routes/studio'
1514
import { Route as DocsImport } from './routes/_docs'
1615
import { Route as DocsIndexImport } from './routes/_docs/index'
16+
import { Route as StudioSplatImport } from './routes/studio/$'
1717
import { Route as DocsIkonerImport } from './routes/_docs/ikoner'
1818
import { Route as DocsKomponenterButtonImport } from './routes/_docs/komponenter/button'
1919
import { Route as DocsKomponenterBadgeImport } from './routes/_docs/komponenter/badge'
2020

2121
// Create/Update Routes
2222

23-
const StudioRoute = StudioImport.update({
24-
id: '/studio',
25-
path: '/studio',
26-
getParentRoute: () => rootRoute,
27-
} as any)
28-
2923
const DocsRoute = DocsImport.update({
3024
id: '/_docs',
3125
getParentRoute: () => rootRoute,
@@ -37,6 +31,12 @@ const DocsIndexRoute = DocsIndexImport.update({
3731
getParentRoute: () => DocsRoute,
3832
} as any)
3933

34+
const StudioSplatRoute = StudioSplatImport.update({
35+
id: '/studio/$',
36+
path: '/studio/$',
37+
getParentRoute: () => rootRoute,
38+
} as any)
39+
4040
const DocsIkonerRoute = DocsIkonerImport.update({
4141
id: '/ikoner',
4242
path: '/ikoner',
@@ -66,20 +66,20 @@ declare module '@tanstack/react-router' {
6666
preLoaderRoute: typeof DocsImport
6767
parentRoute: typeof rootRoute
6868
}
69-
'/studio': {
70-
id: '/studio'
71-
path: '/studio'
72-
fullPath: '/studio'
73-
preLoaderRoute: typeof StudioImport
74-
parentRoute: typeof rootRoute
75-
}
7669
'/_docs/ikoner': {
7770
id: '/_docs/ikoner'
7871
path: '/ikoner'
7972
fullPath: '/ikoner'
8073
preLoaderRoute: typeof DocsIkonerImport
8174
parentRoute: typeof DocsImport
8275
}
76+
'/studio/$': {
77+
id: '/studio/$'
78+
path: '/studio/$'
79+
fullPath: '/studio/$'
80+
preLoaderRoute: typeof StudioSplatImport
81+
parentRoute: typeof rootRoute
82+
}
8383
'/_docs/': {
8484
id: '/_docs/'
8585
path: '/'
@@ -124,16 +124,16 @@ const DocsRouteWithChildren = DocsRoute._addFileChildren(DocsRouteChildren)
124124

125125
export interface FileRoutesByFullPath {
126126
'': typeof DocsRouteWithChildren
127-
'/studio': typeof StudioRoute
128127
'/ikoner': typeof DocsIkonerRoute
128+
'/studio/$': typeof StudioSplatRoute
129129
'/': typeof DocsIndexRoute
130130
'/komponenter/badge': typeof DocsKomponenterBadgeRoute
131131
'/komponenter/button': typeof DocsKomponenterButtonRoute
132132
}
133133

134134
export interface FileRoutesByTo {
135-
'/studio': typeof StudioRoute
136135
'/ikoner': typeof DocsIkonerRoute
136+
'/studio/$': typeof StudioSplatRoute
137137
'/': typeof DocsIndexRoute
138138
'/komponenter/badge': typeof DocsKomponenterBadgeRoute
139139
'/komponenter/button': typeof DocsKomponenterButtonRoute
@@ -142,8 +142,8 @@ export interface FileRoutesByTo {
142142
export interface FileRoutesById {
143143
__root__: typeof rootRoute
144144
'/_docs': typeof DocsRouteWithChildren
145-
'/studio': typeof StudioRoute
146145
'/_docs/ikoner': typeof DocsIkonerRoute
146+
'/studio/$': typeof StudioSplatRoute
147147
'/_docs/': typeof DocsIndexRoute
148148
'/_docs/komponenter/badge': typeof DocsKomponenterBadgeRoute
149149
'/_docs/komponenter/button': typeof DocsKomponenterButtonRoute
@@ -153,18 +153,23 @@ export interface FileRouteTypes {
153153
fileRoutesByFullPath: FileRoutesByFullPath
154154
fullPaths:
155155
| ''
156-
| '/studio'
157156
| '/ikoner'
157+
| '/studio/$'
158158
| '/'
159159
| '/komponenter/badge'
160160
| '/komponenter/button'
161161
fileRoutesByTo: FileRoutesByTo
162-
to: '/studio' | '/ikoner' | '/' | '/komponenter/badge' | '/komponenter/button'
162+
to:
163+
| '/ikoner'
164+
| '/studio/$'
165+
| '/'
166+
| '/komponenter/badge'
167+
| '/komponenter/button'
163168
id:
164169
| '__root__'
165170
| '/_docs'
166-
| '/studio'
167171
| '/_docs/ikoner'
172+
| '/studio/$'
168173
| '/_docs/'
169174
| '/_docs/komponenter/badge'
170175
| '/_docs/komponenter/button'
@@ -173,12 +178,12 @@ export interface FileRouteTypes {
173178

174179
export interface RootRouteChildren {
175180
DocsRoute: typeof DocsRouteWithChildren
176-
StudioRoute: typeof StudioRoute
181+
StudioSplatRoute: typeof StudioSplatRoute
177182
}
178183

179184
const rootRouteChildren: RootRouteChildren = {
180185
DocsRoute: DocsRouteWithChildren,
181-
StudioRoute: StudioRoute,
186+
StudioSplatRoute: StudioSplatRoute,
182187
}
183188

184189
export const routeTree = rootRoute
@@ -192,7 +197,7 @@ export const routeTree = rootRoute
192197
"filePath": "__root.tsx",
193198
"children": [
194199
"/_docs",
195-
"/studio"
200+
"/studio/$"
196201
]
197202
},
198203
"/_docs": {
@@ -204,13 +209,13 @@ export const routeTree = rootRoute
204209
"/_docs/komponenter/button"
205210
]
206211
},
207-
"/studio": {
208-
"filePath": "studio.tsx"
209-
},
210212
"/_docs/ikoner": {
211213
"filePath": "_docs/ikoner.tsx",
212214
"parent": "/_docs"
213215
},
216+
"/studio/$": {
217+
"filePath": "studio/$.tsx"
218+
},
214219
"/_docs/": {
215220
"filePath": "_docs/index.tsx",
216221
"parent": "/_docs"

apps/docs/app/routes/_docs.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import appCss from '@/app.css?url';
1+
import { sanityFetch } from '@/lib/sanity';
2+
import appCss from '@/styles/app.css?url';
23
import { Footer } from '@/ui/footer';
34
import { MainNav } from '@/ui/main-nav';
45
import { GrunnmurenProvider } from '@obosbbl/grunnmuren-react';
@@ -10,6 +11,12 @@ import {
1011
createFileRoute,
1112
useRouter,
1213
} from '@tanstack/react-router';
14+
import { defineQuery } from 'groq';
15+
16+
const COMPONENTS_QUERY = defineQuery(
17+
// make sure the slug is always a string so we don't have add fallback value in code just to make TypeScript happy
18+
`*[_type == "component"]{ _id, name, 'slug': coalesce(slug.current, '')} | order(name asc)`,
19+
);
1320

1421
// This is the shared layout for all the Grunnmuren docs pages that are "public", ie not the Sanity studio
1522
export const Route = createFileRoute('/_docs')({
@@ -22,6 +29,7 @@ export const Route = createFileRoute('/_docs')({
2229
},
2330
],
2431
}),
32+
loader: () => sanityFetch({ query: COMPONENTS_QUERY }),
2533
});
2634

2735
function RootLayout() {

apps/docs/app/routes/studio.tsx

Lines changed: 0 additions & 23 deletions
This file was deleted.

apps/docs/app/routes/studio/$.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// See https://www.sanity.io/docs/embedding-sanity-studio
2+
import cssLink from '@/styles/sanity.css?url';
3+
import { createFileRoute } from '@tanstack/react-router';
4+
import { Studio } from 'sanity';
5+
import sanityConfig from 'sanity.config';
6+
7+
export const Route = createFileRoute('/studio/$')({
8+
head: () => ({
9+
links: [{ rel: 'stylesheet', href: cssLink }],
10+
}),
11+
component: () => <Studio config={sanityConfig} />,
12+
});
File renamed without changes.
File renamed without changes.

apps/docs/app/ui/main-nav.tsx

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ChevronDown } from '@obosbbl/grunnmuren-icons-react';
22
import { Heading } from '@obosbbl/grunnmuren-react';
3+
import { getRouteApi } from '@tanstack/react-router';
34
import { Link } from '@tanstack/react-router';
45
import { Button, Disclosure, DisclosurePanel } from 'react-aria-components';
56

@@ -48,19 +49,6 @@ const MainNavItem = ({ title, subNavItems }: MainNavItemProps) => (
4849
);
4950

5051
const mainNavItems = [
51-
{
52-
title: 'Komponenter',
53-
subNavItems: [
54-
{
55-
to: '/komponenter/badge',
56-
title: 'Badge',
57-
},
58-
{
59-
to: '/komponenter/button',
60-
title: 'Button',
61-
},
62-
],
63-
},
6452
{
6553
title: 'Profil',
6654
subNavItems: [
@@ -72,15 +60,26 @@ const mainNavItems = [
7260
},
7361
];
7462

75-
export const MainNav = () => (
76-
<nav
77-
className="-order-1 w-72 max-w-full bg-sky-lightest px-5 py-9"
78-
aria-label="Navigasjonsmeny for grunnmuren"
79-
>
80-
<ul>
81-
{mainNavItems.map((mainNavItem) => (
82-
<MainNavItem key={mainNavItem.title} {...mainNavItem} />
83-
))}
84-
</ul>
85-
</nav>
86-
);
63+
export const MainNav = () => {
64+
const routeApi = getRouteApi('/_docs');
65+
const { data } = routeApi.useLoaderData();
66+
67+
const componentsNavLinks = data.map((component) => ({
68+
to: `/komponenter/${component.slug}`,
69+
title: component.name as string,
70+
}));
71+
72+
return (
73+
<nav
74+
className="-order-1 w-72 max-w-full bg-sky-lightest px-5 py-9"
75+
aria-label="Navigasjonsmeny for grunnmuren"
76+
>
77+
<ul>
78+
<MainNavItem title="Komponenter" subNavItems={componentsNavLinks} />
79+
{mainNavItems.map((mainNavItem) => (
80+
<MainNavItem key={mainNavItem.title} {...mainNavItem} />
81+
))}
82+
</ul>
83+
</nav>
84+
);
85+
};

apps/docs/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@
1111
"build:assets": "mkdir -p public/resources/icons && cp -r node_modules/@obosbbl/grunnmuren-icons-svg/src/ public/resources/icons",
1212
"build:docgen": "node build-docs.js && prettier --write docgen.ts --ignore-path",
1313
"dev": "vinxi dev",
14-
"start": "vinxi start"
14+
"start": "vinxi start",
15+
"typegen:extract": "sanity schema extract",
16+
"typegen:generate": "sanity typegen generate"
1517
},
1618
"dependencies": {
1719
"@code-obos/sanity-auth": "1.4.0",
1820
"@obosbbl/grunnmuren-icons-react": "workspace:*",
1921
"@obosbbl/grunnmuren-icons-svg": "workspace:*",
2022
"@obosbbl/grunnmuren-react": "workspace:*",
23+
"@sanity/client": "6.24.1",
24+
"@sanity/vision": "3.68.3",
2125
"@tanstack/react-router": "1.95.1",
2226
"@tanstack/start": "1.95.1",
2327
"cva": "1.0.0-beta.2",
28+
"groq": "3.68.3",
2429
"prism-react-renderer": "2.4.1",
2530
"react": "19.0.0",
2631
"react-aria-components": "1.5.0",

apps/docs/sanity.config.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { obosAuthStore } from '@code-obos/sanity-auth';
2+
import { visionTool } from '@sanity/vision';
3+
import { defineConfig } from 'sanity';
4+
import { structureTool } from 'sanity/structure';
5+
import { schemaTypes } from './studio/schema-types';
6+
7+
const dataset = 'grunnmuren';
8+
9+
export default defineConfig({
10+
projectId: 'tq6w17ny',
11+
dataset: 'grunnmuren',
12+
basePath: '/studio',
13+
title: 'Grunnmuren - Sanity Studio',
14+
auth: obosAuthStore({ dataset }),
15+
plugins: [structureTool(), visionTool()],
16+
schema: {
17+
types: schemaTypes,
18+
},
19+
});

0 commit comments

Comments
 (0)