14.8 KB
collections.html
{{template "docs.html" .}}
{{define "title"}}Collections{{end}}
{{define "content"}}
<article class="space-y-12">
<header>
<div class="w-12 h-1 rounded-full bg-gradient-to-r from-violet-500 to-cyan-500 mb-6"></div>
<h1 class="text-3xl font-bold text-white mb-3">Collections</h1>
<p class="text-[#888] text-lg">Structured content for your site — blog posts, products, team members, and more.</p>
</header>
<section class="space-y-6">
<div>
<h2 class="text-xl font-semibold text-white">What are Collections?</h2>
<p class="text-[#888] mt-2">Collections are containers for your structured content. Think of them as spreadsheets where each column has a type — text, number, date, and more. You create a collection, define its fields, then add records through the admin UI, the <a href="/docs/ai-assistant" class="text-violet-400 hover:text-violet-300">AI assistant</a>, or the <a href="/docs/api" class="text-violet-400 hover:text-violet-300">REST API</a>.</p>
</div>
<div class="grid sm:grid-cols-3 gap-4">
<div class="border border-white/10 rounded-lg p-5">
<div class="text-violet-400 font-medium mb-2">Define Schema</div>
<p class="text-sm text-[#888]">Create collections with typed fields — text, number, boolean, date, select, and more.</p>
</div>
<div class="border border-white/10 rounded-lg p-5">
<div class="text-cyan-400 font-medium mb-2">Manage Records</div>
<p class="text-sm text-[#888]">Add, edit, and delete records through the admin UI or the REST API.</p>
</div>
<div class="border border-white/10 rounded-lg p-5">
<div class="text-emerald-400 font-medium mb-2">Use in Templates</div>
<p class="text-sm text-[#888]">Query records directly in your page templates with built-in functions.</p>
</div>
</div>
</section>
<section class="space-y-6">
<h2 class="text-xl font-semibold text-white">Schema Field Types</h2>
<div class="grid sm:grid-cols-2 gap-3">
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">text</code>
<div>
<p class="text-sm text-white">Short or long text</p>
<p class="text-xs text-[#666] mt-0.5">"Hello world"</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">number</code>
<div>
<p class="text-sm text-white">Integer or decimal</p>
<p class="text-xs text-[#666] mt-0.5">42</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">bool</code>
<div>
<p class="text-sm text-white">True or false</p>
<p class="text-xs text-[#666] mt-0.5">true</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">date</code>
<div>
<p class="text-sm text-white">Date and time</p>
<p class="text-xs text-[#666] mt-0.5">"2024-01-15T10:30:00Z"</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">select</code>
<div>
<p class="text-sm text-white">Single choice from options</p>
<p class="text-xs text-[#666] mt-0.5">"published"</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">email</code>
<div>
<p class="text-sm text-white">Email address</p>
<p class="text-xs text-[#666] mt-0.5">"user@example.com"</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">url</code>
<div>
<p class="text-sm text-white">Web URL</p>
<p class="text-xs text-[#666] mt-0.5">"https://example.com"</p>
</div>
</div>
<div class="border border-white/10 rounded-lg p-4 flex items-start gap-3">
<code class="text-xs text-violet-400 bg-violet-400/10 px-2 py-1 rounded flex-shrink-0">json</code>
<div>
<p class="text-sm text-white">Raw JSON data</p>
<p class="text-xs text-[#666] mt-0.5">{"key": "value"}</p>
</div>
</div>
</div>
</section>
<section class="space-y-6">
<h2 class="text-xl font-semibold text-white">Using Collections in Templates</h2>
<p class="text-[#888]">Access your collection data directly in page templates with built-in functions.</p>
<div class="space-y-4">
<div class="border border-white/10 rounded-lg p-4">
<div class="text-sm text-white font-medium mb-2">List all records from a collection</div>
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]">{{"{{range $post := documents \"blog-posts\"}}"}}
<h2>{{"{{$post.GetString \"title\"}}"}}</h2>
<p>{{"{{$post.GetString \"content\"}}"}}</p>
{{"{{end}}"}}</code></pre>
</div>
<div class="border border-white/10 rounded-lg p-4">
<div class="text-sm text-white font-medium mb-2">Get a single record by ID</div>
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]">{{"{{with document \"record-id\"}}"}}
<h1>{{"{{.GetString \"title\"}}"}}</h1>
<span>Price: ${{"{{.GetInt \"price\"}}"}}</span>
{{"{{end}}"}}</code></pre>
</div>
<div class="border border-white/10 rounded-lg p-4">
<div class="text-sm text-white font-medium mb-2">Access record data by type</div>
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]">{{"{{$doc.GetString \"title\"}}"}} {{"{{"}}/* text fields */{{"}}"}}
{{"{{$doc.GetInt \"count\"}}"}} {{"{{"}}/* number fields */{{"}}"}}
{{"{{$doc.GetBool \"published\"}}"}} {{"{{"}}/* boolean fields */{{"}}"}}
{{"{{$doc.GetTime \"createdAt\"}}"}} {{"{{"}}/* date fields */{{"}}"}}
{{"{{$doc.GetStrings \"tags\"}}"}} {{"{{"}}/* array fields */{{"}}"}}</code></pre>
</div>
</div>
</section>
<!-- Info callout before API -->
<div class="flex gap-3 p-4 rounded-lg border border-cyan-400/20 bg-cyan-400/[0.03]">
<svg class="w-5 h-5 text-cyan-400 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
<div>
<span class="text-cyan-400 font-medium text-sm">Note</span>
<p class="text-sm text-[#888] mt-1">The REST API lets you manage records programmatically. Use it to sync data from external systems, build custom integrations, or automate content workflows.</p>
</div>
</div>
<section class="space-y-6" id="api">
<div class="border-t border-white/10 pt-8">
<h2 class="text-xl font-semibold text-white">REST API</h2>
<p class="text-[#888] mt-2">Manage records programmatically via the API. See the <a href="/docs/api" class="text-violet-400 hover:underline">API Reference</a> for authentication details.</p>
</div>
<div class="space-y-4">
<div class="border border-white/10 rounded-lg p-4">
<div class="flex items-center gap-3 mb-2">
<span class="text-xs font-medium px-2 py-0.5 rounded bg-emerald-400/10 text-emerald-400">GET</span>
<code class="text-sm text-white">/api/collections/{collectionId}/records</code>
</div>
<p class="text-sm text-[#888]">List all records in a collection.</p>
</div>
<div class="border border-white/10 rounded-lg p-4">
<div class="flex items-center gap-3 mb-2">
<span class="text-xs font-medium px-2 py-0.5 rounded bg-blue-400/10 text-blue-400">POST</span>
<code class="text-sm text-white">/api/collections/{collectionId}/records</code>
</div>
<p class="text-sm text-[#888]">Create a new record. Send field values as JSON body.</p>
</div>
<div class="border border-white/10 rounded-lg p-4">
<div class="flex items-center gap-3 mb-2">
<span class="text-xs font-medium px-2 py-0.5 rounded bg-amber-400/10 text-amber-400">PATCH</span>
<code class="text-sm text-white">/api/collections/{collectionId}/records/{recordId}</code>
</div>
<p class="text-sm text-[#888]">Update an existing record.</p>
</div>
<div class="border border-white/10 rounded-lg p-4">
<div class="flex items-center gap-3 mb-2">
<span class="text-xs font-medium px-2 py-0.5 rounded bg-red-400/10 text-red-400">DELETE</span>
<code class="text-sm text-white">/api/collections/{collectionId}/records/{recordId}</code>
</div>
<p class="text-sm text-[#888]">Delete a record.</p>
</div>
</div>
</section>
<section class="space-y-6">
<h2 class="text-xl font-semibold text-white">Access Rules</h2>
<p class="text-[#888]">Control who can read, create, update, and delete records with rule expressions.</p>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-white/10">
<th class="text-left text-[#888] py-3 pr-4">Rule</th>
<th class="text-left text-[#888] py-3">Meaning</th>
</tr>
</thead>
<tbody class="text-[#ccc]">
<tr class="border-b border-white/5">
<td class="py-3 pr-4"><code class="text-violet-400">""</code> (empty)</td>
<td class="py-3">Admin only (default)</td>
</tr>
<tr class="border-b border-white/5">
<td class="py-3 pr-4"><code class="text-violet-400">"true"</code></td>
<td class="py-3">Anyone (public access)</td>
</tr>
<tr class="border-b border-white/5">
<td class="py-3 pr-4"><code class="text-violet-400">"@request.auth != nil"</code></td>
<td class="py-3">Any authenticated user</td>
</tr>
<tr>
<td class="py-3 pr-4"><code class="text-violet-400">"@request.auth.role = 'admin'"</code></td>
<td class="py-3">Admin users only</td>
</tr>
</tbody>
</table>
</div>
<p class="text-sm text-[#888]">Rules are set per-collection in the admin dashboard under Settings.</p>
</section>
<section class="space-y-4">
<h2 class="text-xl font-semibold text-white">Example: Blog Posts</h2>
<div class="border border-white/10 rounded-lg p-5 space-y-3">
<div class="text-white font-medium">Schema</div>
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]">[
{"name": "title", "type": "text", "required": true},
{"name": "content", "type": "text", "required": true},
{"name": "author", "type": "text", "required": false},
{"name": "published", "type": "bool", "required": false},
{"name": "tags", "type": "json", "required": false}
]</code></pre>
</div>
<div class="border border-white/10 rounded-lg p-5 space-y-3">
<div class="text-white font-medium">Page Template</div>
<pre class="bg-[#1a1a1a] border border-white/10 rounded-lg p-4 text-sm overflow-x-auto"><code class="text-[#e5e5e5]"><div class="blog">
{{"{{range $post := documents \"blog-posts\"}}"}}
{{"{{if $post.GetBool \"published\"}}"}}
<article>
<h2>{{"{{$post.GetString \"title\"}}"}}</h2>
<p class="author">By {{"{{$post.GetString \"author\"}}"}}</p>
<div>{{"{{$post.GetString \"content\"}}"}}</div>
</article>
{{"{{end}}"}}
{{"{{end}}"}}
</div></code></pre>
</div>
</section>
<!-- What's Next -->
<section class="border-t border-white/10 pt-12 space-y-4">
<h2 class="text-xl font-semibold text-white">What's next?</h2>
<div class="grid sm:grid-cols-2 gap-4">
<a href="/docs/templates" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-emerald-400 font-medium mb-1">Templates</div>
<p class="text-sm text-[#888]">Use template functions to display collection data on your pages.</p>
</a>
<a href="/docs/api" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-cyan-400 font-medium mb-1">API Reference</div>
<p class="text-sm text-[#888]">Full REST API documentation for records, auth, and real-time events.</p>
</a>
<a href="/docs/endpoints" class="border border-white/10 rounded-lg p-5 hover:border-white/20 hover:bg-white/[0.02] transition-all">
<div class="text-pink-400 font-medium mb-1">Endpoints</div>
<p class="text-sm text-[#888]">Write custom API logic with serverless Lua scripts.</p>
</a>
</div>
</section>
</article>
{{end}}