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
499 changes: 499 additions & 0 deletions .agents/docs.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,6 @@ For deeper context, see `.agents/`:
- [`.agents/presets.md`](.agents/presets.md) — All 31 presets, preset structure, how to create presets, resolution logic.
- [`.agents/testing.md`](.agents/testing.md) — Test structure, how tests work, adding regression tests, running tests.
- [`.agents/vite.md`](.agents/vite.md) — Vite build system: plugin architecture (6 sub-plugins), environments API, dev server integration, production build stages, bundler config, HMR, runtime worker.
- [`.agents/docs.md`](.agents/docs.md) — Documentation conventions: structure, preset naming (underscore), H3 v2 API patterns, import paths, common mistakes.

- **Important:** H3 v2 updated docs is at `node_modules/h3/skills/h3/docs/TOC.md`
25 changes: 24 additions & 1 deletion docs/.config/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,34 @@ socials:
discord: https://discord.nitro.build
sponsors:
api: https://sponsors.pi0.io/sponsors.json
redirects:
# v2 guide → v3 docs
"/guide": "/docs"
"/guide/getting-started": "/docs"
"/guide/utils": "/docs/routing"
"/guide/routing": "/docs/routing"
"/guide/websocket": "/docs/routing"
"/guide/cache": "/docs/cache"
"/guide/storage": "/docs/storage"
"/guide/database": "/docs/database"
"/guide/fetch": "/docs/routing"
"/guide/assets": "/docs/assets"
"/guide/plugins": "/docs/plugins"
"/guide/configuration": "/docs/configuration"
"/guide/typescript": "/docs/configuration"
"/guide/tasks": "/docs/tasks"
"/guide/nightly": "/docs/nightly"
# v2 deploy
"/deploy/workers": "/deploy"
"/deploy/runtimes/winterjs": "/deploy"
"/deploy/custom-presets": "/deploy"
"/deploy/providers/edgio": "/deploy"
"/deploy/node": "/deploy/runtimes/node"
themeColor: "rose"
automd: true
branch: main
versions:
- label: "v3 (alpha)"
- label: "v3 (beta)"
active: true
- label: "v2"
to: "https://nitro.build"
11 changes: 11 additions & 0 deletions docs/.docs/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineAppConfig } from "#imports"

export default defineAppConfig({
ui: {
button: {
slots: {
base: 'active:translate-y-px transition-transform duration-300',
},
},
},
})
23 changes: 23 additions & 0 deletions docs/.docs/assets/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
:root {
--font-sans: "Geist", sans-serif !important;
--font-mono: "Geist Mono", monospace !important;
}

h1[data-slot="title"] {
font-family: "Geist Pixels", sans-serif !important;
}

.landing-code {
--ui-bg-muted: #0c0c0e;
--ui-border-muted: #27272a;
--ui-bg: #0c0c0e;
}

.landing-code pre[style] {
background-color: #0c0c0e !important;
}

.landing-code > div > div {
margin-top: 0;
margin-bottom: 0;
}
Binary file added docs/.docs/assets/fonts/GeistPixel-Square.woff2
Binary file not shown.
62 changes: 62 additions & 0 deletions docs/.docs/components/AppHero.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script setup lang="ts">
defineProps<{
title: string
description: string
primaryLink: string
primaryLabel: string
githubLink: string
codeGroups: {
filename: string
code: string
}[]
}>()
</script>

<template>
<UPageHero orientation="horizontal">
<template #default>
<div class="code-group">
<ProseCodeGroup>
<ProsePre
v-for="group in codeGroups"
:key="group.filename"
:filename="group.filename"
language="ts"
>
<pre>{{ group.code }}</pre>
</ProsePre>
</ProseCodeGroup>
</div>
</template>

<HeroBackground />

<template #title>
<span v-html="title" />
</template>

<template #description>
{{ description }}
</template>

<template #links>
<UButton
size="xl"
:to="primaryLink"
trailing-icon="i-lucide-arrow-right"
>
{{ primaryLabel }}
</UButton>
<UButton
color="neutral"
icon="i-simple-icons-github"
size="xl"
target="_blank"
:to="githubLink"
variant="outline"
>
GitHub
</UButton>
</template>
</UPageHero>
</template>
49 changes: 49 additions & 0 deletions docs/.docs/components/AppHeroLinks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<div class="flex flex-wrap items-center justify-center gap-4">
<UButton
size="xl"
to="/docs/quick-start"
trailing-icon="i-lucide-arrow-right"
>
Get started
</UButton>
<UButton
color="neutral"
icon="i-simple-icons-github"
size="xl"
target="_blank"
to="https://github.com/nitrojs/nitro"
variant="outline"
>
Star on GitHub
</UButton>
<a
:href="`${baseURL}llms.txt`"
target="_blank"
class="basis-full text-sm text-muted hover:text-default transition-colors inline-flex items-center justify-center gap-1"
@click.prevent="copyPrompt"
>
<UIcon :name="copied ? 'i-lucide-clipboard-check' : 'i-lucide-bot'" />
Docs for AI
</a>
</div>
</template>

<script setup lang="ts">
const copied = ref(false)
const baseURL = computed(() => {
if (import.meta.client) {
return `${window.location.origin}/`
}
return '/'
})

function copyPrompt() {
const text = `Read nitro docs from ${baseURL.value}docs/quick-start so I can ask questions about it.`
navigator.clipboard.writeText(text)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
}
</script>
51 changes: 51 additions & 0 deletions docs/.docs/components/FeatureCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
import { Motion } from 'motion-v'

defineProps<{
headline?: string
link?: string
linkLabel?: string
}>()

const prefersReducedMotion = ref(false)

onMounted(() => {
prefersReducedMotion.value = window.matchMedia('(prefers-reduced-motion: reduce)').matches
})
</script>

<template>
<Motion
:initial="prefersReducedMotion ? { opacity: 1 } : { opacity: 0, y: 20 }"
:while-in-view="{ opacity: 1, y: 0 }"
:transition="{ duration: 0.5 }"
:in-view-options="{ once: true }"
>
<NuxtLink :to="link" class="block h-full" :class="link ? 'cursor-pointer' : 'cursor-default'">
<div class="relative overflow-hidden rounded-xl border border-default bg-white/60 dark:bg-neutral-900/60 backdrop-blur-sm p-8 h-full transition-all duration-300 hover:shadow-lg hover:-translate-y-1">
<div v-if="headline" class="text-xs font-mono uppercase tracking-widest text-primary mb-4 flex items-center gap-2">
<span class="inline-block w-1 h-1 rounded-full bg-primary" />
{{ headline }}
</div>

<h3 class="text-2xl font-bold text-neutral-900 dark:text-white mb-3 tracking-tight">
<slot name="title" />
</h3>

<p class="text-neutral-500 dark:text-neutral-400 text-sm leading-relaxed mb-6">
<slot name="description" />
</p>

<slot name="demo" />

<span
v-if="link"
class="inline-flex items-center gap-1 text-sm text-primary mt-auto"
>
{{ linkLabel || 'Learn more' }}
<UIcon name="i-lucide-arrow-right" class="size-4" />
</span>
</div>
</NuxtLink>
</Motion>
</template>
18 changes: 16 additions & 2 deletions docs/.docs/components/HeroBackground.client.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
<script setup lang="ts">
import { Shader, ChromaFlow } from 'shaders/vue'
import { ref, onMounted, defineAsyncComponent } from 'vue'

const Shader = defineAsyncComponent(() => import('shaders/vue').then(m => m.Shader))
const ChromaFlow = defineAsyncComponent(() => import('shaders/vue').then(m => m.ChromaFlow))

const enabled = ref(false)

onMounted(() => {
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent) || window.innerWidth < 768
const hasWebGPU = 'gpu' in navigator
const lowMemory = (navigator as any).deviceMemory !== undefined && (navigator as any).deviceMemory < 4
const lowCores = navigator.hardwareConcurrency !== undefined && navigator.hardwareConcurrency < 4

enabled.value = hasWebGPU && !isMobile && !lowMemory && !lowCores
})
</script>

<template>
<Shader class="absolute inset-0 w-full h-full -z-10">
<Shader v-if="enabled" class="absolute inset-0 w-full h-full -z-10">
<ChromaFlow
base-color="oklch(71.2% 0.194 13.428)"
up-color="oklch(70.2% 0.183 293.541)"
Expand Down
75 changes: 75 additions & 0 deletions docs/.docs/components/HeroFeatures.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<script setup lang="ts">
import { Motion } from 'motion-v'

const props = defineProps<{
features: {
title: string
description: string
icon: string
color: string
bgColor: string
borderColor: string
}[]
}>()

const prefersReducedMotion = ref(false)

function randomLines() {
const count = 2 + Math.floor(Math.random() * 3)
return Array.from({ length: count }, (_, j) => ({
width: `${20 + Math.floor(Math.random() * 80)}%`,
delay: j * 0.1,
}))
}

const featureLines = computed(() => props.features.map(() => randomLines()))

onMounted(() => {
prefersReducedMotion.value = window.matchMedia('(prefers-reduced-motion: reduce)').matches
})
</script>

<template>
<section class="relative bg-neutral-50 dark:bg-neutral-950/30 py-14 border-y border-default">
<UContainer>
<div class="grid md:grid-cols-3 gap-6">
<Motion
v-for="(feature, i) in features"
:key="feature.title"
:initial="prefersReducedMotion ? { opacity: 1 } : { opacity: 0, y: 16 }"
:while-in-view="{ opacity: 1, y: 0 }"
:transition="{ duration: 0.4, delay: i * 0.1 }"
:in-view-options="{ once: true }"
>
<div :class="['group relative rounded-xl border border-default bg-white/80 dark:bg-neutral-900/50 p-6 h-full transition-all duration-300 hover:shadow-md', feature.borderColor]">
<div class="flex items-center gap-3 mb-3">
<div :class="[feature.bgColor, 'w-9 h-9 rounded-lg flex items-center justify-center shrink-0']">
<UIcon :name="feature.icon" :class="[feature.color, 'text-lg']" />
</div>
<h3 class="text-lg font-bold text-neutral-900 dark:text-white tracking-tight">
{{ feature.title }}
</h3>
</div>

<p class="text-sm text-neutral-500 dark:text-neutral-400 leading-relaxed mb-4">
{{ feature.description }}
</p>

<div class="flex flex-col gap-1.5">
<Motion
v-for="(line, j) in featureLines[i]"
:key="j"
:initial="{ width: '0%', opacity: 0 }"
:while-in-view="{ width: line.width, opacity: 1 }"
:transition="{ duration: 0.8, delay: 0.3 + line.delay + i * 0.1 }"
:in-view-options="{ once: true }"
>
<div :class="[feature.bgColor, 'h-1 rounded-full']" />
</Motion>
</div>
</div>
</Motion>
</div>
</UContainer>
</section>
</template>
21 changes: 21 additions & 0 deletions docs/.docs/components/LandingFeatures.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<section class="relative bg-neutral-50 dark:bg-neutral-950/30 py-20 md:py-28">
<div class="absolute inset-0 dotted-bg" />
<div class="relative max-w-6xl mx-auto px-6">
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
<slot name="body" />
</div>
</div>
</section>
</template>

<style scoped>
.dotted-bg {
background-image: radial-gradient(circle, rgb(0 0 0 / 0.1) 1px, transparent 1px);
background-size: 20px 20px;
}

:root.dark .dotted-bg {
background-image: radial-gradient(circle, rgb(255 255 255 / 0.07) 1px, transparent 1px);
}
</style>
Loading
Loading