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
4 changes: 4 additions & 0 deletions .changeset/ultracite-8-formatting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Formatting only: apply the blank-line spacing that ultracite 8 enforces and write the Redis field pattern with `\w`. No change in behaviour, so no release.
2 changes: 2 additions & 0 deletions apps/web/app/changelog/rss.xml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const escapeXml = (value: string): string =>

const handler = () => {
const entries = getChangelogEntries();

const items = entries
.map(
(entry) => ` <item>
Expand All @@ -23,6 +24,7 @@ const handler = () => {
</item>`
)
.join("\n");

const lastBuildDate = entries[0]?.data.date.toUTCString() ?? "";

const feed = `<?xml version="1.0" encoding="UTF-8"?>
Expand Down
1 change: 1 addition & 0 deletions apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { fonts } from "@/lib/fonts";
import { url } from "@/lib/url";

const siteName = "VecStore SDK";

const siteDescription =
"A unified vector store SDK for TypeScript. One filter language across Qdrant, pgvector, Pinecone, Supabase, Upstash Vector, Cloudflare Vectorize, and Redis, so you can switch providers without rewriting queries.";

Expand Down
1 change: 1 addition & 0 deletions apps/web/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const revalidate = false;

const handler = async () => {
const pages = await Promise.all(source.getPages().map(getLLMText));

return new Response(pages.join("\n\n"), {
headers: { "Content-Type": "text/plain" },
});
Expand Down
2 changes: 2 additions & 0 deletions apps/web/app/og/docs/[...slug]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ const backgrounds = path.join(process.cwd(), "app", "og", "docs", "[...slug]");

const readBackground = (slugs: readonly string[]) => {
const [group, name] = slugs;

const provider =
group === "providers" && providerIds.some((id) => id === name)
? name
: undefined;

const file = provider ? `background-${provider}.png` : "background.png";

return readFile(path.join(backgrounds, file));
Expand Down
29 changes: 29 additions & 0 deletions apps/web/components/brand-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ const MENU_GAP = 8;

const serialize = (svg: SVGSVGElement): string => {
const clone = svg.cloneNode(true);

if (!(clone instanceof SVGSVGElement)) {
return "";
}

const ink = document.documentElement.classList.contains("dark")
? "#ededed"
: "#171717";

clone.removeAttribute("class");
clone.removeAttribute("aria-hidden");
clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");

return new XMLSerializer()
.serializeToString(clone)
.replaceAll("currentColor", ink);
Expand All @@ -44,7 +48,9 @@ const CopyTile = ({
if (status === "idle") {
return;
}

const timer = window.setTimeout(() => setStatus("idle"), COPIED_MS);

return () => window.clearTimeout(timer);
}, [status]);

Expand All @@ -53,9 +59,11 @@ const CopyTile = ({
className="text-gray-1000 hover:bg-gray-alpha-100 flex min-w-0 flex-col gap-2 rounded-md p-2 text-left text-[14px] transition-colors"
onClick={async (event) => {
event.stopPropagation();

if (!svgRef.current) {
return;
}

try {
await navigator.clipboard.writeText(serialize(svgRef.current));
setStatus("copied");
Expand Down Expand Up @@ -98,18 +106,23 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => {

useEffect(() => {
const anchor = anchorRef.current?.closest("a") ?? anchorRef.current;

if (!anchor) {
return;
}

anchor.setAttribute("aria-haspopup", "menu");
anchor.setAttribute("aria-controls", menuId);

const handle = (event: Event) => {
event.preventDefault();
const rect = anchor.getBoundingClientRect();
setPosition({ left: rect.left, top: rect.bottom + MENU_GAP });
setOpen(true);
};

anchor.addEventListener("contextmenu", handle);

return () => anchor.removeEventListener("contextmenu", handle);
}, [menuId]);

Expand All @@ -122,23 +135,29 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => {
if (!open) {
return;
}

menuRef.current?.querySelector<HTMLElement>("[role=menuitem]")?.focus();

const close = (event: Event) => {
if (event instanceof KeyboardEvent && event.key !== "Escape") {
return;
}

if (
event instanceof PointerEvent &&
event.target instanceof Node &&
menuRef.current?.contains(event.target)
) {
return;
}

setOpen(false);
(anchorRef.current?.closest("a") ?? anchorRef.current)?.focus();
};

document.addEventListener("keydown", close);
document.addEventListener("pointerdown", close);

return () => {
document.removeEventListener("keydown", close);
document.removeEventListener("pointerdown", close);
Expand All @@ -148,34 +167,44 @@ export const BrandMenu = ({ children }: { readonly children: ReactNode }) => {
const moveFocus = (event: KeyboardEvent<HTMLDivElement>) => {
if (event.key === "Tab") {
setOpen(false);

return;
}

const items = [
...(menuRef.current?.querySelectorAll<HTMLElement>("[role=menuitem]") ??
[]),
];

const active = document.activeElement;
const index = active instanceof HTMLElement ? items.indexOf(active) : -1;

const resolveTarget = (): HTMLElement | undefined => {
switch (event.key) {
case "ArrowDown": {
return items.at((index + 1) % items.length);
}

case "ArrowUp": {
return items.at((index - 1 + items.length) % items.length);
}

case "End": {
return items.at(-1);
}

case "Home": {
return items[0];
}

default: {
return undefined;
}
}
};

const target = resolveTarget();

if (target) {
event.preventDefault();
target.focus();
Expand Down
3 changes: 3 additions & 0 deletions apps/web/components/docs/sidebar-items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ const containsPath = (
if (node.type === "page") {
return node.url === pathname;
}

if (node.type === "folder") {
return (
node.index?.url === pathname || containsPath(node.children, pathname)
);
}

return false;
});

export const Item = ({ item }: { readonly item: PageTreeItem }) => {
const pathname = usePathname();

return (
<SidebarItem
active={pathname === item.url}
Expand Down
1 change: 1 addition & 0 deletions apps/web/components/landing/copy-command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const CopyCommand = ({
const [copied, onCopy] = useCopyButton(() =>
navigator.clipboard.writeText(command)
);

const Icon = copied ? CheckIcon : CopyIcon;

return (
Expand Down
2 changes: 2 additions & 0 deletions apps/web/components/landing/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const Demo = async () => {
await renderCode(provider.snippet(example.filterCode)),
])
);

return {
code: Object.fromEntries(entries),
expression: example.expression,
Expand All @@ -56,6 +57,7 @@ export const Demo = async () => {
};
})
);

const providers = demoProviders.map(({ id, label }) => ({ id, label }));

return <HeroDemo examples={examples} providers={providers} />;
Expand Down
6 changes: 6 additions & 0 deletions apps/web/components/landing/hero-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,19 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => {
useLayoutEffect(() => {
const measure = () => {
const tab = tabRefs.current[exampleIndex];

if (tab) {
setIndicator({ left: tab.offsetLeft, width: tab.offsetWidth });
}
};

measure();
const observer = new ResizeObserver(measure);

if (listRef.current) {
observer.observe(listRef.current);
}

return () => observer.disconnect();
}, [exampleIndex]);
const example = examples[exampleIndex] ?? examples[0];
Expand All @@ -77,6 +81,7 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => {

const selectProvider = (id: string) => {
const index = providers.findIndex((item) => item.id === id);

if (index !== -1) {
setProviderIndex(index);
}
Expand All @@ -103,6 +108,7 @@ export const HeroDemo = ({ providers, examples }: HeroDemoProps) => {
/>
{examples.map((item, index) => {
const active = index === exampleIndex;

return (
<button
aria-selected={active}
Expand Down
Loading
Loading