Skip to content

Commit 37dfeed

Browse files
Docs Updates #4 - Move Framework Content (#669)
* update all dependencies * add packageManager back * remove hardcoded url * wip * cleanup from review * cleanup again * switch to json for storing redirects * convert to ts * cleanup * ai cleanup * Update README.md * backfill all ids * feat(nav): rename Connect→APIs, Automate→Flows, Manage→Hosting * feat(llms): rename guide section titles to APIs and Flows * docs: replace branded "Directus Connect"/"Directus Automate" with APIs/Flows * docs(homepage): drop Data Engine/Data Studio framing * fix: fold 11.integrations into 12.integrations to clear numeric collision * fix sidebar * docs(nav): rename Guides→Guide, Hosting→Deploy * kill editor and explorer * initial moves * wippity * cleanup * fix nav * extract findNavNode * vanilla to vanilla js * fix claude bs * oops technologies is needed for the imaages * add chips to tutorials with framworks * more cleanup * All Frameworks * docs: clean up flows terminology * Reuse injected navigation on frameworks page
1 parent c7e7c33 commit 37dfeed

126 files changed

Lines changed: 1911 additions & 418 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.githooks/pre-push

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,9 @@ if ! git fetch origin main --quiet; then
55
echo "warning: failed to fetch origin/main; using local ref for redirect check" >&2
66
fi
77

8-
if git rev-parse --verify origin/main >/dev/null 2>&1; then
9-
base_ref="origin/main"
10-
elif git rev-parse --verify main >/dev/null 2>&1; then
11-
base_ref="main"
12-
else
13-
echo "warning: no origin/main or main ref found; skipping redirect check" >&2
14-
exit 0
15-
fi
16-
17-
if git diff --quiet "$base_ref"...HEAD -- content redirects.json content.config.ts; then
8+
if git diff --quiet origin/main...HEAD -- content redirects.json content.config.ts; then
189
exit 0
1910
fi
2011

2112
echo "Checking redirects for docs changes..."
22-
pnpm redirects:check -- --base "$base_ref"
13+
pnpm redirects:check

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ logs
2727
.vercel
2828

2929
.vscode
30+
31+
.claude/scheduled_tasks.lock

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,33 @@ pnpm typecheck:scripts # Type check repository scripts
6161

6262
`pnpm install` configures `.githooks` for the repository when no custom `core.hooksPath` is set. The pre-commit hook can add missing `stableId` values to staged docs files. The pre-push hook checks redirects when docs content, redirect configuration, or content configuration changes.
6363

64+
## ✍️ Authoring Content
65+
66+
Pages live as Markdown files under `content/`. Frontmatter fields are validated by the schema in `content.config.ts`.
67+
68+
### Framework Guides
69+
70+
Framework guides live under `content/frameworks/<framework>/`. The numeric prefix on filenames (`01.`, `02.`, …) controls sidebar sort order only — it has no semantic meaning, renumber freely.
71+
72+
The `section` frontmatter field controls grouping on the `/frameworks/<framework>` hub page:
73+
74+
- `section: start-here` — appears in the "Start Here" block at the top.
75+
- `section: guides` (or unset) — appears in the "Guides" block below.
76+
77+
Minimal frontmatter for a new framework guide:
78+
79+
```yaml
80+
---
81+
title: Fetch Data from Directus with Foo
82+
description: Learn how to integrate Directus in your Foo app.
83+
section: start-here
84+
technologies:
85+
- foo
86+
navigation:
87+
title: Data Fetching
88+
---
89+
```
90+
6491
## ☁️ Deploying the Docs
6592

6693
The documentation automatically deploys to Vercel when changes are merged into the main branch. Simply:

app/app.config.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export default defineAppConfig({
107107
],
108108
},
109109
{
110-
label: 'Deploy',
110+
label: 'Hosting',
111111
children: [
112112
{
113113
label: 'Cloud',
@@ -129,6 +129,16 @@ export default defineAppConfig({
129129
{
130130
label: 'Resources',
131131
children: [
132+
{
133+
label: 'Frameworks',
134+
to: '/frameworks',
135+
icon: 'i-ph-brackets-curly',
136+
},
137+
{
138+
label: 'Tutorials',
139+
to: '/tutorials',
140+
icon: 'i-ph-article',
141+
},
132142
{
133143
label: 'Community',
134144
to: '/community/overview/welcome',
@@ -139,11 +149,6 @@ export default defineAppConfig({
139149
to: '/releases',
140150
icon: 'i-ph-notebook',
141151
},
142-
{
143-
label: 'Tutorials',
144-
to: '/tutorials',
145-
icon: 'i-ph-article',
146-
},
147152
],
148153
},
149154
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
items: Array<{ title: string; description?: string; path: string }>;
4+
}>();
5+
</script>
6+
7+
<template>
8+
<ul class="divide-y divide-default rounded-lg border border-default">
9+
<li
10+
v-for="item in items"
11+
:key="item.path"
12+
class="p-4 transition hover:bg-muted/50"
13+
>
14+
<NuxtLink
15+
:to="item.path"
16+
class="group flex items-start justify-between gap-4"
17+
>
18+
<span>
19+
<span class="font-semibold text-highlighted group-hover:text-primary">
20+
{{ item.title }}
21+
</span>
22+
<span
23+
v-if="item.description"
24+
class="mt-1 block text-sm text-muted"
25+
>
26+
{{ item.description }}
27+
</span>
28+
</span>
29+
<Icon
30+
name="i-ph-arrow-right"
31+
class="mt-1 size-4 shrink-0 text-muted transition group-hover:translate-x-0.5 group-hover:text-primary"
32+
/>
33+
</NuxtLink>
34+
</li>
35+
</ul>
36+
</template>

app/components/TutorialsArticles.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const props = defineProps<{
44
limit?: number;
55
}>();
66
7-
const { data: articles } = await useAsyncData(props.path + '-preview', () => {
7+
const { data: articles } = await useAsyncData(`${props.path}-articles-${props.limit ?? 'all'}`, () => {
88
const query = queryCollection('content')
99
.where('path', 'LIKE', `${props.path}/%`)
1010
.select('title', 'description', 'icon', 'path', 'technologies', 'navigation');
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<script setup lang="ts">
2+
import type { ContentNavigationItem } from '@nuxt/content';
3+
4+
const props = defineProps<{
5+
slug: string;
6+
}>();
7+
8+
const navigation = inject('navigation') as Ref<ContentNavigationItem[]> | undefined;
9+
10+
const frameworkLabel = computed(() => {
11+
const node = findNavNode(navigation?.value, `/frameworks/${props.slug}`);
12+
return node?.title ?? props.slug;
13+
});
14+
15+
const { data: guides } = await useAsyncData(`framework-${props.slug}-guides`, () =>
16+
queryCollection('content')
17+
.where('path', 'LIKE', `/frameworks/${props.slug}/%`)
18+
.where('path', 'NOT LIKE', '%/.navigation')
19+
.where('stem', 'NOT LIKE', '%/index')
20+
.select('title', 'description', 'path', 'navigation', 'section', 'stem')
21+
.order('stem', 'ASC')
22+
.all(),
23+
);
24+
25+
const { data: tutorials } = await useAsyncData(`framework-${props.slug}-tutorials`, () =>
26+
queryCollection('content')
27+
.where('path', 'LIKE', '/tutorials/%')
28+
.select('title', 'description', 'path', 'technologies')
29+
.all(),
30+
);
31+
32+
type LinkItem = {
33+
title: string;
34+
description?: string;
35+
path: string;
36+
};
37+
38+
const guideTitle = (g: { title: string; navigation?: unknown }) => {
39+
if (g.navigation && typeof g.navigation === 'object' && 'title' in g.navigation) {
40+
const navTitle = (g.navigation as { title?: string }).title;
41+
if (navTitle) return navTitle;
42+
}
43+
return g.title;
44+
};
45+
46+
const visibleGuides = computed(() => (guides.value ?? [])
47+
.filter(g => g.navigation !== false));
48+
49+
const startHere = computed<LinkItem[]>(() =>
50+
visibleGuides.value
51+
.filter(g => g.section === 'start-here')
52+
.map(g => ({ title: guideTitle(g), description: g.description, path: g.path })));
53+
54+
const moreGuides = computed<LinkItem[]>(() =>
55+
visibleGuides.value
56+
.filter(g => g.section !== 'start-here')
57+
.map(g => ({ title: guideTitle(g), description: g.description, path: g.path })));
58+
59+
const matchingTutorials = computed<LinkItem[]>(() => (tutorials.value ?? [])
60+
.filter(t => Array.isArray(t.technologies) && t.technologies.includes(props.slug))
61+
.sort((a, b) => a.title.localeCompare(b.title))
62+
.map(t => ({ title: t.title, description: t.description, path: t.path })));
63+
</script>
64+
65+
<template>
66+
<div class="not-prose space-y-10">
67+
<section v-if="startHere.length">
68+
<ProseH2 id="start-here">
69+
Start Here
70+
</ProseH2>
71+
<FrameworkLinkList :items="startHere" />
72+
</section>
73+
74+
<section v-if="moreGuides.length">
75+
<ProseH2 id="guides">
76+
Guides
77+
</ProseH2>
78+
<FrameworkLinkList :items="moreGuides" />
79+
</section>
80+
81+
<section v-if="matchingTutorials.length">
82+
<ProseH2 id="framework-tutorials">
83+
{{ frameworkLabel }} Tutorials
84+
</ProseH2>
85+
<FrameworkLinkList :items="matchingTutorials" />
86+
</section>
87+
</div>
88+
</template>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<script setup lang="ts">
2+
import type { ContentNavigationItem } from '@nuxt/content';
3+
4+
const navigation = inject('navigation') as Ref<ContentNavigationItem[]> | undefined;
5+
6+
const frameworks = computed(() => {
7+
const root = findNavNode(navigation?.value, '/frameworks');
8+
return (root?.children ?? [])
9+
.filter(item => item.path && item.path !== '/frameworks')
10+
.map(item => ({
11+
label: item.title,
12+
path: item.path,
13+
icon: item.icon,
14+
}));
15+
});
16+
</script>
17+
18+
<template>
19+
<div class="not-prose grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-3 my-5">
20+
<NuxtLink
21+
v-for="framework in frameworks"
22+
:key="framework.path"
23+
:to="framework.path"
24+
class="group flex items-center gap-3 rounded-lg border border-default p-3 transition hover:bg-primary/5 hover:ring hover:ring-primary"
25+
>
26+
<Icon
27+
v-if="framework.icon"
28+
:name="framework.icon"
29+
class="size-5 shrink-0 text-muted group-hover:text-primary"
30+
/>
31+
<span class="text-sm font-semibold text-highlighted group-hover:text-primary">
32+
{{ framework.label }}
33+
</span>
34+
</NuxtLink>
35+
</div>
36+
</template>

0 commit comments

Comments
 (0)