Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cb01a2c
Open in LLM feature
cycle4passion Jan 4, 2026
d11704b
removed grok
cycle4passion Jan 4, 2026
9867588
open-in-llm-component
cycle4passion Jan 7, 2026
a5c924e
Merge branch 'docs-v2' into open-in-llm-component
cycle4passion Jan 7, 2026
d44d6f1
minor copy change
cycle4passion Jan 7, 2026
b207674
used markdown icons
cycle4passion Jan 7, 2026
0b97b36
llms.txt - 3 levels
cycle4passion Jan 23, 2026
9c8a128
fix spelling error
cycle4passion Jan 24, 2026
eb51725
another spelling fix
cycle4passion Jan 24, 2026
3a91975
Change OpenLLMs.svelte to OpenWithButton.svelte
cycle4passion Jan 26, 2026
5fd96e1
Change "View Page Markdown" to open in modal
techniq Jan 31, 2026
12d69c5
refine OpenWithButton
techniq Jan 31, 2026
7595f7d
update `p` markdown component to only apply margins when within main …
techniq Jan 31, 2026
5bd1d0e
refine some wording
techniq Jan 31, 2026
b4a658f
Create guides content collection and use to build menu
techniq Jan 31, 2026
a1edc7d
Extract and consolidate common llms.txt utils
techniq Feb 1, 2026
8852b77
Add common sortCollection util
techniq Feb 1, 2026
df0b8cb
add component links to examples llms.txt
techniq Feb 1, 2026
f48bbd7
consolidate more logic into llms/utils.ts
techniq Feb 1, 2026
1e27cc0
Replace `fs`/`path` usage with Vite's `import.meta.glob`
techniq Feb 1, 2026
b812f53
Move processMarkdownContent to llms/utils.ts
techniq Feb 1, 2026
7a94117
processMarkdownContent within generateComponentMarkdown / generateUti…
techniq Feb 1, 2026
1636528
include `:example { }`directives
techniq Feb 1, 2026
90b0c17
cleanup
techniq Feb 1, 2026
70a518d
move related section to bottom of component docs (also matches llms.txt)
techniq Feb 1, 2026
e613d0a
Add examples to component llms.txt
techniq Feb 1, 2026
af80b70
Rename `Component docs` to just `Components` when viewing an example
techniq Feb 1, 2026
1ad0d18
Extract generateExampleMarkdown from request handler into llms/tuils.ts
techniq Feb 1, 2026
12b6cf0
move generateFullLlmsTxt to llms/utils.ts, always use markdownRespons…
techniq Feb 1, 2026
d610ecd
move generateLlmsTxt to llms/utils.ts,
techniq Feb 1, 2026
13465f9
replace generateGuidesSection with generateCollectionListSection
techniq Feb 1, 2026
f543dd7
Uwe docsUrl in `inlineExampleDirectives` and `generateComponentMarkdo…
techniq Feb 1, 2026
67fd89b
remove unneeded exports
techniq Feb 1, 2026
c9d9a8c
cleanup types
techniq Feb 1, 2026
70dc379
Merge branch 'docs-v2' into pr/cycle4passion/753
techniq Feb 1, 2026
901fe50
delete outdated tests
techniq Feb 1, 2026
68ec8f2
update docs test setup to match packages/layerchart
techniq Feb 1, 2026
ee7a433
add llms tests and add to ci
techniq Feb 1, 2026
e99decd
Add LLMs link to frontpage footer
techniq Feb 1, 2026
c3da9f1
Update LLMs docs
techniq Feb 1, 2026
275aff2
Disable docs tests until contentCollections() can be enabled without …
techniq Feb 1, 2026
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
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,37 @@ jobs:
env:
CI: true

# test-docs-server-ssr:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: pnpm/action-setup@v4.0.0
# - uses: actions/setup-node@v4
# with:
# node-version: ${{ env.NODE_VERSION }}
# cache: pnpm
# - run: pnpm install --frozen-lockfile
# - name: Run docs unit tests (server + ssr)
# run: pnpm --filter docs test:unit --project server --project ssr
# env:
# CI: true

# test-docs-browser:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: pnpm/action-setup@v4.0.0
# - uses: actions/setup-node@v4
# with:
# node-version: ${{ env.NODE_VERSION }}
# cache: pnpm
# - run: pnpm install --frozen-lockfile
# - run: pnpm --filter docs exec playwright install chromium
# - name: Run docs browser tests (client)
# run: pnpm --filter docs test:unit --project client
# env:
# CI: true

build:
runs-on: ubuntu-latest
steps:
Expand Down
22 changes: 21 additions & 1 deletion docs/content-collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,26 @@ const utils = defineCollection({
}
});

const guides = defineCollection({
name: 'guides',
directory: 'src/content/guides',
include: '**/*.md',
schema: z.object({
title: z.string(),
description: z.string().optional(),
order: z.number().optional(),
draft: z.boolean().default(false)
}),
transform: async (doc) => {
const { path } = doc._meta;
return {
...doc,
name: doc.title,
slug: path
};
}
});

const releases = defineCollection({
name: 'releases',
directory: 'src/content/releases',
Expand All @@ -181,5 +201,5 @@ const releases = defineCollection({
});

export default defineConfig({
collections: [components, examples, utils, releases]
collections: [components, examples, utils, guides, releases]
});
52 changes: 52 additions & 0 deletions docs/src/content/guides/LLMs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: LLMs
order: 8
---

<script>
import OpenWithButton from "$lib/components/OpenWithButton.svelte";
</script>

The LayerChart documentation pages are designed to be accessible for humans developers using LLMs as well as large language models (LLMs) ingesting training data.

## :icon{name="lucide:user" class="relative -top-1"} For the Humans

<OpenWithButton example/>

At the top of each documentation page, and demonstrated above, you will find a button which copies the content of the page's documentation in Markdown to the clipboard. The convenient dropdown also gives you additional helpful options, such as viewing the component source or opening in chat.

::note
The option for `View Component Source` is only shown for component pages.
::

## :icon{name="lucide:bot" class="relative -top-1"} For the Bots

LayerChart adopts the [llms.txt](https://llmstxt.org/) proposal standard, which provides a structured, machine-readable format optimized for LLMs. This enables developers, researchers, and AI systems to efficiently parse and utilize our documentation.

::note
Most but not all pages support the `/llms.txt` suffix (i.e. those deemed irrelevant to LLMs).
::

## LLM-friendly Documentation 3 Ways

::steps

## Per page / component

To access the LLM-friendly version of supported documentation pages, simply append `/llms.txt` to the end of the page's URL. This will return the content in a plain-text, LLM-optimized format. This is the same text which is copied to the clipboard when you click the `Copy Page` button.

:::tip
**Standard Page**: The LineChart component documentation is available at [/docs/components/LineChart](/docs/components/LineChart)

**LLM-friendly Version**: is available at [/docs/components/LineChart/llms.txt](/docs/components/LineChart/llms.txt)
:::

## Root Index

To explore all supported pages in LLM-friendly format, visit the root index at [llms.txt](/llms.txt). This page provides a comprehensive list of available documentation endpoints compatible with the `llms.txt` standard.

## Complete Documentation

For a complete, consolidated view of the all the documentation in an LLM-friendly format, navigate to [/docs/llms.txt](/docs/llms.txt). This single endpoint aggregates all documentation content into a machine-readable structure, ideal for bulk processing or ingestion into AI systems.

::
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Features
---
title: Features
order: 1
---

> WIP

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
---
title: Layers
order: 2
---

<script lang="ts">
import FeatureTable from './FeatureTable.svelte';
import FeatureTable from './layers/FeatureTable.svelte';

import { graphics, styles, gradient, text, other } from './features';
import { graphics, styles, gradient, text, other } from './layers/features';
</script>

# Layers

LayerChart provides first-class support for different types of layers including [Svg](/docs/components/Svg), [Html](/docs/components/Html), and [Canvas](/docs/components/Canvas) via [Layer](/docs/components/Layer) and [Primitive](/docs/guides/primitives) components.

Each layer type provides unique and overlapping feature sets. LayerChart supports using layers of different types within the same chart to leverage a type's strengths or workaround a weakness.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
---
title: Primitives
order: 3
---

<script lang="ts">
import { allComponents } from 'content-collections';
import ComponentLink from '$lib/components/ComponentLink.svelte';

let primitiveComponents = allComponents.filter(c => c.category === 'primitives');
</script>

# Primitives

A collection of components which support rendering within different layer types including `Svg`, `Canvas`, or `Html`.

Support for each layer type is dependent on the primitive's feature needs and capabilities of the layer type.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
---
title: Scales
order: 5
---

<script lang="ts">
import { scaleLinear } from 'd3-scale';
import { format } from '@layerstack/utils';

import Code from '$lib/components/Code.svelte';
import DomainRangeChart from './DomainRangeChart.svelte';
import DomainRangeChart from './scales/DomainRangeChart.svelte';

let domain = $state([100, 400]);
let range = $state([0, 500]);
Expand All @@ -22,8 +27,6 @@
let [minRange, maxRange] = $derived(range);
</script>

# Scales

## What is a scale?

At its essence, a scale is a function that maps data values (`domain`) to pixel or color values (`range`) on a per-dimension basis (`x`, `y`, `color`, etc).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Simplified Charts
order: 4
---

<script lang="ts">
import Code from '$lib/components/Code.svelte';
import Example from '$lib/components/Example.svelte';
Expand All @@ -11,8 +16,6 @@
`)
</script>

# Simplified charts

The LayerChart project was written to offer options for both flexibility/complexity as well as approachablilty/simplicity. This brings us to a decision as you start your first LayerChart.

## Use `<Chart>` or `Simple Chart`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# State / Context
---
title: State / Context
order: 6
---

> TODO

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# Styling
---
title: Styling
order: 7
---

## Colors

Colors represent the main style requirement for Layerchart.

Instead of requiring explicit color props for each element, LayerChart leverages CSSs [CSS currentColor](https://www.digitalocean.com/community/tutorials/css-currentcolor) under the hood. This allows developers to style charts using familiar, standard CSS color utilities, rather than targeting different attributes for each rendering layer (svg, canvas, or html).
Instead of requiring explicit color props for each element, LayerChart leverages CSS's [CSS currentColor](https://www.digitalocean.com/community/tutorials/css-currentcolor) under the hood. This allows developers to style charts using familiar, standard CSS color utilities, rather than targeting different attributes for each rendering layer (svg, canvas, or html).

Color is simply inherited and propagated through the component tree, and LayerChart automatically applies it appropriately for each display layer—using `fill` or `stroke` for SVG, `fillStyle`, `fillRect` for canvas, and `color` or `background-color` for HTML.

Expand Down Expand Up @@ -212,7 +215,7 @@ Picking a color isn't easy. Picking many colors that appear cohesive is even tou
more info [Color Schemes](/docs/components/ColorRamp#schemes)
::

:example{ path="./color-schemes.svelte" noResize showCode highight="40" }
:example{ path="./styles/color-schemes.svelte" noResize showCode highight="40" }

#### Data Driven Colors (choropleth, color prop on data for pie chart, etc)

Expand Down Expand Up @@ -253,4 +256,4 @@ more info [Color Schemes](/docs/components/ColorRamp#schemes)
Chart padding is the only other commonly styled element.
`Can xPadding and yPadding be added to example below?`

:example{ path="./padding.svelte" noResize }
:example{ path="./styles/padding.svelte" noResize }
7 changes: 0 additions & 7 deletions docs/src/demo.spec.ts

This file was deleted.

12 changes: 12 additions & 0 deletions docs/src/lib/collections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Sort a collection by optional `order` field first (items with order come before those without),
* then alphabetically by `name`.
*/
export function sortCollection<T extends { order?: number; name: string }>(items: T[]): T[] {
return items.slice().sort((a, b) => {
if (a.order !== undefined && b.order !== undefined) return a.order - b.order;
if (a.order !== undefined) return -1;
if (b.order !== undefined) return 1;
return a.name.localeCompare(b.name);
});
}
2 changes: 1 addition & 1 deletion docs/src/lib/components/Code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

createHighlighter({
themes: ['github-light-default', 'github-dark-default'],
langs: ['svelte', 'javascript', 'ts', 'typescript', 'json', 'sh']
langs: ['svelte', 'javascript', 'ts', 'typescript', 'json', 'sh', 'md']
}).then((h) => {
highlighter = h;
});
Expand Down
28 changes: 6 additions & 22 deletions docs/src/lib/components/DocsMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import { NavItem, type IconProp } from 'svelte-ux';
import { flatGroup } from 'd3-array';

import { allComponents, allUtils } from 'content-collections';
import { allComponents, allUtils, allGuides } from 'content-collections';
import { sortCollection } from '$lib/collections';
import { page } from '$app/state';
import { sortFunc } from '@layerstack/utils';
import { cls } from '@layerstack/tailwind';

import LucideBot from '~icons/lucide/bot';
import LucideCompass from '~icons/lucide/compass';
import LucideGalleryVertical from '~icons/lucide/gallery-vertical';
import LucideGalleryHorizontalEnd from '~icons/lucide/gallery-horizontal-end';
Expand All @@ -21,15 +23,7 @@

let { onItemClick, class: className }: { onItemClick?: () => void; class?: string } = $props();

const guides = [
{ name: 'Features', path: 'features' },
{ name: 'Layers', path: 'layers' },
{ name: 'Primitives', path: 'primitives' },
{ name: 'Simplified charts', path: 'simplified-charts' },
{ name: 'Scales', path: 'scales' },
{ name: 'State', path: 'state' },
{ name: 'Styles', path: 'styles' }
];
const guides = sortCollection(allGuides.filter((g) => !g.draft));

const componentsByCategory = flatGroup(allComponents, (d) => d.category?.toLowerCase())
.filter(([category]) => category !== 'examples')
Expand Down Expand Up @@ -84,7 +78,7 @@
</h2>
<div class="border-l border-surface-content/10">
{#each guides as guide}
{@render navItem({ label: guide.name, path: `/docs/guides/${guide.path}` })}
{@render navItem({ label: guide.name, path: `/docs/guides/${guide.slug}` })}
{/each}
</div>
</section>
Expand All @@ -97,17 +91,7 @@
<div class="mb-6 last:mb-0">
<h3 class="text-surface-content/80 mb-3 text-sm font-medium capitalize">{category}</h3>
<div class="border-l border-surface-content/10">
{#each components.sort((a, b) => {
// If both have order, sort by order
if (a.order !== undefined && b.order !== undefined) {
return a.order - b.order;
}
// Items with order come first
if (a.order !== undefined) return -1;
if (b.order !== undefined) return 1;
// Both without order, sort alphabetically by name
return a.name.localeCompare(b.name);
}) as component}
{#each sortCollection(components) as component}
{@render navItem({ label: component.name, path: `/docs/components/${component.slug}` })}
{/each}
</div>
Expand Down
5 changes: 5 additions & 0 deletions docs/src/lib/components/Example.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
* Resolve a relative or absolute path to a full path from /src
*/
function resolveExamplePath(examplePath: string, currentPath: string): string {
const isGuide = currentPath.startsWith('/docs/guides/');
if (isGuide && (examplePath.startsWith('./') || !examplePath.startsWith('/'))) {
const relativePath = examplePath.startsWith('./') ? examplePath.slice(2) : examplePath;
return `/src/content/guides/${relativePath}`;
}
if (examplePath.startsWith('./')) {
return `/src/routes${currentPath}/${examplePath.slice(2)}`;
} else if (examplePath.startsWith('/')) {
Expand Down
Loading
Loading