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
204 changes: 204 additions & 0 deletions components/diagrams.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import {
Clock3,
FileText,
FolderClosed,
MessageSquareText,
Users,
} from 'lucide-react';

function Layer({
label,
detail,
icon: Icon,
emphasis = false,
}: {
label: string;
detail: string;
icon: typeof FolderClosed;
emphasis?: boolean;
}) {
return (
<div
className={
emphasis
? 'rounded-lg border border-fd-primary/30 bg-fd-primary/10 p-3'
: 'rounded-lg border bg-fd-background p-3'
}
>
<div className="flex items-center gap-2">
<Icon aria-hidden="true" className="size-4 shrink-0 text-fd-primary" />
<span className="font-medium text-fd-foreground">{label}</span>
</div>
<p className="mt-1 text-xs leading-relaxed text-fd-muted-foreground">
{detail}
</p>
</div>
);
}

function ProjectMemory({ name }: { name: string }) {
return (
<div className="rounded-xl border bg-fd-card p-3">
<div className="mb-3 flex items-center gap-2 text-sm font-medium text-fd-foreground">
<FolderClosed aria-hidden="true" className="size-4 text-fd-primary" />
{name}
<span className="ms-auto rounded-full bg-fd-muted px-2 py-0.5 text-[11px] font-normal text-fd-muted-foreground">
private scope
</span>
</div>
<div className="space-y-2">
<Layer
label="Project context"
detail="Durable facts, decisions, and conventions"
icon={FileText}
/>
<Layer
label="Working memory"
detail="Recent activity, open items, and files touched"
icon={Clock3}
/>
</div>
</div>
);
}

export function MemoryScopeDiagram() {
return (
<figure
aria-labelledby="memory-scope-caption"
className="not-prose my-6 rounded-xl border bg-fd-muted/30 p-4 sm:p-5"
>
<Layer
label="Global preferences"
detail="Your timezone, response style, and standing instructions apply in every project"
icon={Users}
emphasis
/>

<div aria-hidden="true" className="mx-auto h-5 w-px bg-fd-border" />
<div className="grid gap-3 sm:grid-cols-2">
<ProjectMemory name="Project A" />
<ProjectMemory name="Project B" />
</div>

<figcaption
id="memory-scope-caption"
className="mt-4 text-center text-xs leading-relaxed text-fd-muted-foreground"
>
Global preferences apply everywhere. Project context and working memory
stay inside their project.
</figcaption>
</figure>
);
}

const graphNodes = [
{ label: 'People', x: 104, y: 86, icon: Users },
{ label: 'Meetings', x: 318, y: 62, icon: MessageSquareText },
{ label: 'Decisions', x: 532, y: 130, icon: FileText },
{ label: 'Files', x: 340, y: 230, icon: FileText },
{ label: 'Projects', x: 118, y: 226, icon: FolderClosed },
] as const;

const graphEdges = [
[0, 1],
[0, 4],
[1, 2],
[1, 3],
[1, 4],
[2, 3],
[3, 4],
] as const;

export function KnowledgeGraphDiagram() {
return (
<figure
aria-labelledby="knowledge-graph-caption"
className="not-prose my-6 overflow-hidden rounded-xl border bg-fd-muted/30 p-3 sm:p-5"
>
<svg
role="img"
aria-labelledby="knowledge-graph-title knowledge-graph-description"
className="h-auto w-full"
viewBox="0 0 640 340"
>
<title id="knowledge-graph-title">How the knowledge graph grows</title>
<desc id="knowledge-graph-description">
People, meetings, decisions, files, and projects form connected nodes.
The connections accumulate over time.
</desc>

<g className="stroke-fd-border" strokeWidth="2">
{graphEdges.map(([from, to]) => (
<line
key={`${from}-${to}`}
x1={graphNodes[from].x}
y1={graphNodes[from].y}
x2={graphNodes[to].x}
y2={graphNodes[to].y}
/>
))}
</g>

{graphNodes.map(({ label, x, y, icon: Icon }) => (
<g key={label} transform={`translate(${x} ${y})`}>
<circle
className="fill-fd-card stroke-fd-primary/40"
r="42"
strokeWidth="2"
/>
<Icon
aria-hidden="true"
className="text-fd-primary"
x="-10"
y="-19"
width="20"
height="20"
/>
<text
className="fill-fd-foreground text-[13px] font-medium"
textAnchor="middle"
y="17"
>
{label}
</text>
</g>
))}

<g transform="translate(62 302)">
<line
className="stroke-fd-muted-foreground/40"
x1="0"
y1="0"
x2="516"
y2="0"
strokeWidth="2"
/>
<path
className="fill-fd-muted-foreground/40"
d="M516 0 505 -6 505 6Z"
/>
<text className="fill-fd-muted-foreground text-[12px]" x="0" y="22">
First conversations
</text>
<text
className="fill-fd-muted-foreground text-[12px]"
x="516"
y="22"
textAnchor="end"
>
More connected context
</text>
</g>
</svg>

<figcaption
id="knowledge-graph-caption"
className="mt-1 text-center text-xs leading-relaxed text-fd-muted-foreground"
>
Fluso connects people, meetings, decisions, files, and projects as it
works with them.
</figcaption>
</figure>
);
}
2 changes: 2 additions & 0 deletions components/mdx.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import defaultMdxComponents from 'fumadocs-ui/mdx';
import type { MDXComponents } from 'mdx/types';
import * as diagrams from '@/components/diagrams';
import * as mintlify from '@/components/mintlify';

export function getMDXComponents(components?: MDXComponents) {
return {
...defaultMdxComponents,
...diagrams,
...mintlify,
...components,
} satisfies MDXComponents;
Expand Down
13 changes: 13 additions & 0 deletions components/mintlify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ import { cn } from '@/lib/cn';
*/

function LucideIcon({ name, className }: { name: string; className?: string }) {
if (name === 'github') {
return (
<svg
aria-hidden="true"
className={className}
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2.1c-3.3.7-4-1.4-4-1.4-.5-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.4 11.4 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3Z" />
</svg>
);
}

const pascal = name
.split('-')
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
Expand Down
9 changes: 8 additions & 1 deletion components/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,12 @@ import { RootProvider } from 'fumadocs-ui/provider/next';
import { type ReactNode } from 'react';

export function Provider({ children }: { children: ReactNode }) {
return <RootProvider search={{ SearchDialog }}>{children}</RootProvider>;
return (
<RootProvider
search={{ SearchDialog }}
theme={{ defaultTheme: 'light', enableSystem: true }}
>
{children}
</RootProvider>
);
}
4 changes: 1 addition & 3 deletions content/docs/features/memory.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ Durable memory follows a stricter rule than you might expect: it saves stable th

## Three layers

<Note>
**Diagram —** Three layers shown with their scope: **Global preferences** (widest reach), **Project context** (durable, scoped to one project), and **Project working memory** (recent activity, also project-scoped). Visual should make clear that project material does not leak into other projects.
</Note>
<MemoryScopeDiagram />

**Global preferences.** User-level things that should apply everywhere. Your timezone, the response style you have asked for, workflow choices, standing instructions like *"always show me drafts in plain text"*. These live in `preferences.md` in your workspace, where you can read them.

Expand Down
2 changes: 2 additions & 0 deletions content/docs/going-deeper.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ The full mechanics are in [Skills](/features/skills). The bar for building one i

Memory builds itself in the background. You do not have to maintain it. A few habits keep it useful and on-scope. The mechanics are in [Memory](/features/memory) — this is what to do with them.

<KnowledgeGraphDiagram />

**Be explicit when something is durable.** *"Remember that I prefer drafts in plain text"*, *"add to project context: the Q3 launch ships on August 14"*. Background learning is conservative on purpose; explicit asks are the fast path.

**Tell Fluso to forget when you need to.** *"Forget my old timezone"*, *"don't track anything about this vendor"*. The same explicit channel works in reverse.
Expand Down
1 change: 1 addition & 0 deletions content/docs/release-notes.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
title: "Release notes"
icon: sparkles
description: "What's new in Fluso - product updates, improvements, and fixes."
---

Expand Down
51 changes: 51 additions & 0 deletions lib/layout.shared.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
import Image from 'next/image';

function GitHubIcon() {
return (
<svg role="img" viewBox="0 0 24 24" fill="currentColor">
<title>GitHub</title>
<path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2.1c-3.3.7-4-1.4-4-1.4-.5-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.4 11.4 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3Z" />
</svg>
);
}

function XIcon() {
return (
<svg role="img" viewBox="0 0 24 24" fill="currentColor">
<title>X</title>
<path d="M18.9 2H22l-6.8 7.8L23.2 22H17l-4.9-6.4L6.5 22H3.3l7.3-8.3L3 2h6.3l4.4 5.8L18.9 2Zm-1.1 17.8h1.7L8.4 4.1H6.6l11.2 15.7Z" />
</svg>
);
}

function LinkedInIcon() {
return (
<svg role="img" viewBox="0 0 24 24" fill="currentColor">
<title>LinkedIn</title>
<path d="M20.5 3H3.5A2.5 2.5 0 0 0 1 5.5v13A2.5 2.5 0 0 0 3.5 21h17a2.5 2.5 0 0 0 2.5-2.5v-13A2.5 2.5 0 0 0 20.5 3ZM8 18H5V9h3v9ZM6.5 7.8A1.8 1.8 0 1 1 6.5 4a1.8 1.8 0 0 1 0 3.8ZM19 18h-3v-4.4c0-1.1 0-2.4-1.5-2.4S13 12.3 13 13.5V18h-3V9h2.9v1.2h.1a3.2 3.2 0 0 1 2.9-1.6c3.1 0 3.7 2 3.7 4.7V18H19Z" />
</svg>
);
}

export function baseOptions(): BaseLayoutProps {
return {
nav: {
Expand Down Expand Up @@ -30,6 +57,30 @@ export function baseOptions(): BaseLayoutProps {
text: 'Download',
url: 'https://fluso.ai/',
},
{
type: 'icon',
text: 'X',
label: 'Fluso on X',
url: 'https://twitter.com/premai_io',
icon: <XIcon />,
external: true,
},
{
type: 'icon',
text: 'GitHub',
label: 'Fluso on GitHub',
url: 'https://github.com/premAI-io',
icon: <GitHubIcon />,
external: true,
},
{
type: 'icon',
text: 'LinkedIn',
label: 'Fluso on LinkedIn',
url: 'https://linkedin.com/company/premai',
icon: <LinkedInIcon />,
external: true,
},
],
};
}
13 changes: 13 additions & 0 deletions lib/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { loader } from 'fumadocs-core/source';
import { docsContentRoute, docsImageRoute, docsRoute } from './shared';
import { defineDocs } from 'fumadocs-mdx/macro';
import { metaSchema, pageSchema } from 'fumadocs-core/source/schema';
import { icons } from 'lucide-react';
import { createElement, type ComponentType } from 'react';

const docs = defineDocs({
dir: 'content/docs',
Expand All @@ -21,6 +23,17 @@ export const source = loader({
baseUrl: docsRoute,
source: docs.toFumadocsSource(),
plugins: [],
icon(icon) {
if (!icon) return;
const pascal = icon
.split('-')
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join('');
const Icon = (icons as Record<string, ComponentType<{ className?: string }>>)[
pascal
];
return Icon ? createElement(Icon) : undefined;
},
});

export function getPageImageUrl(page: (typeof source)['$inferPage']) {
Expand Down
Loading