@stampui/blocks 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ai-chat-shell.d.ts +1 -0
- package/dist/components/ai-chat-shell.js +23 -0
- package/dist/components/prompt-input.d.ts +5 -0
- package/dist/components/prompt-input.js +47 -0
- package/dist/components/registry-card.d.ts +6 -0
- package/dist/components/registry-card.js +15 -0
- package/dist/components/registry-explorer.d.ts +8 -0
- package/dist/components/registry-explorer.js +38 -0
- package/dist/components/token-stream.d.ts +7 -0
- package/dist/components/token-stream.js +21 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +23 -0
- package/dist/manifests.d.ts +3 -0
- package/dist/manifests.js +1666 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +2 -0
- package/package.json +28 -0
- package/src/components/blocks/ai-chat-shell.tsx +97 -0
- package/src/components/blocks/auth-panel.tsx +203 -0
- package/src/components/blocks/feature-grid.tsx +122 -0
- package/src/components/blocks/hero-section.tsx +73 -0
- package/src/components/blocks/notification-center.tsx +185 -0
- package/src/components/blocks/onboarding-flow.tsx +230 -0
- package/src/components/blocks/pricing-section.tsx +135 -0
- package/src/components/blocks/project-command-center.tsx +188 -0
- package/src/components/blocks/prompt-input.tsx +81 -0
- package/src/components/blocks/registry-card.tsx +104 -0
- package/src/components/blocks/registry-explorer.tsx +78 -0
- package/src/components/blocks/settings-layout.tsx +178 -0
- package/src/components/blocks/stats-strip.tsx +100 -0
- package/src/components/blocks/token-stream.tsx +42 -0
- package/src/components/blocks/usage-card.tsx +116 -0
- package/src/components/core/accordion.tsx +58 -0
- package/src/components/core/alert-dialog.tsx +113 -0
- package/src/components/core/alert.tsx +48 -0
- package/src/components/core/animated-number.tsx +77 -0
- package/src/components/core/aspect-ratio.tsx +20 -0
- package/src/components/core/avatar-stack.tsx +61 -0
- package/src/components/core/avatar.tsx +90 -0
- package/src/components/core/badge.tsx +39 -0
- package/src/components/core/breadcrumb.tsx +63 -0
- package/src/components/core/button-group.tsx +37 -0
- package/src/components/core/button.tsx +110 -0
- package/src/components/core/calendar.tsx +143 -0
- package/src/components/core/card.tsx +60 -0
- package/src/components/core/carousel.tsx +170 -0
- package/src/components/core/chart.tsx +377 -0
- package/src/components/core/checkbox.tsx +64 -0
- package/src/components/core/collapsible.tsx +30 -0
- package/src/components/core/combobox.tsx +114 -0
- package/src/components/core/command-box.tsx +22 -0
- package/src/components/core/command.tsx +165 -0
- package/src/components/core/confirm-action.tsx +94 -0
- package/src/components/core/context-menu.tsx +139 -0
- package/src/components/core/copy-button.tsx +41 -0
- package/src/components/core/data-table.tsx +173 -0
- package/src/components/core/date-picker.tsx +73 -0
- package/src/components/core/dialog.tsx +83 -0
- package/src/components/core/drawer.tsx +87 -0
- package/src/components/core/dropdown-menu.tsx +147 -0
- package/src/components/core/empty.tsx +34 -0
- package/src/components/core/field.tsx +39 -0
- package/src/components/core/file-upload.tsx +143 -0
- package/src/components/core/hover-card.tsx +31 -0
- package/src/components/core/inline-edit.tsx +104 -0
- package/src/components/core/input-group.tsx +47 -0
- package/src/components/core/input-otp.tsx +108 -0
- package/src/components/core/input.tsx +37 -0
- package/src/components/core/kbd.tsx +47 -0
- package/src/components/core/label.tsx +28 -0
- package/src/components/core/marquee.tsx +61 -0
- package/src/components/core/menubar.tsx +120 -0
- package/src/components/core/multi-select.tsx +145 -0
- package/src/components/core/native-select.tsx +27 -0
- package/src/components/core/navigation-menu.tsx +130 -0
- package/src/components/core/number-stepper.tsx +80 -0
- package/src/components/core/pagination.tsx +80 -0
- package/src/components/core/password-input.tsx +90 -0
- package/src/components/core/popover.tsx +34 -0
- package/src/components/core/progress.tsx +63 -0
- package/src/components/core/radio-group.tsx +77 -0
- package/src/components/core/resizable.tsx +250 -0
- package/src/components/core/scroll-area.tsx +38 -0
- package/src/components/core/select.tsx +128 -0
- package/src/components/core/separator.tsx +47 -0
- package/src/components/core/sheet.tsx +118 -0
- package/src/components/core/sidebar.tsx +129 -0
- package/src/components/core/skeleton.tsx +32 -0
- package/src/components/core/slider.tsx +97 -0
- package/src/components/core/sonner.tsx +29 -0
- package/src/components/core/spinner.tsx +60 -0
- package/src/components/core/status-pulse.tsx +67 -0
- package/src/components/core/stepper.tsx +111 -0
- package/src/components/core/switch.tsx +72 -0
- package/src/components/core/table.tsx +104 -0
- package/src/components/core/tabs.tsx +55 -0
- package/src/components/core/tag-input.tsx +93 -0
- package/src/components/core/textarea.tsx +44 -0
- package/src/components/core/timeline.tsx +81 -0
- package/src/components/core/toggle-group.tsx +56 -0
- package/src/components/core/toggle.tsx +66 -0
- package/src/components/core/tooltip.tsx +31 -0
- package/src/components/core/typing-indicator.tsx +51 -0
- package/src/index.ts +8 -0
- package/src/manifests.ts +1682 -0
- package/src/types.ts +58 -0
- package/src/ui.ts +13 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function AIChatShell(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Menu, Plus, MessageSquare, Settings } from "lucide-react";
|
|
5
|
+
import { cx } from "@/lib/cx";
|
|
6
|
+
import { Button } from "@/components/core/button";
|
|
7
|
+
import { PromptInput } from "@/components/blocks/prompt-input";
|
|
8
|
+
import { TokenStream } from "@/components/blocks/token-stream";
|
|
9
|
+
export function AIChatShell() {
|
|
10
|
+
const [sidebarOpen, setSidebarOpen] = React.useState(true);
|
|
11
|
+
const [messages, setMessages] = React.useState([
|
|
12
|
+
{ role: "assistant", content: "Hello! I am ready to help you build your next app. What would you like to create today?" }
|
|
13
|
+
]);
|
|
14
|
+
const handleSubmit = (val) => {
|
|
15
|
+
setMessages([...messages, { role: "user", content: val }]);
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
setMessages(prev => [...prev, { role: "assistant", content: "I can certainly help with that! Let's break down the requirements..." }]);
|
|
18
|
+
}, 600);
|
|
19
|
+
};
|
|
20
|
+
return (_jsxs("div", { className: "flex h-[600px] w-full overflow-hidden rounded-xl border border-border bg-background shadow-xl", children: [_jsxs("div", { className: cx("flex flex-col border-r border-border bg-muted/20 transition-all duration-300", sidebarOpen ? "w-64" : "w-0 overflow-hidden border-r-0"), children: [_jsxs("div", { className: "flex h-14 items-center justify-between px-4 border-b border-border", children: [_jsx("span", { className: "font-semibold text-sm", children: "Chats" }), _jsx(Button, { variant: "quiet", size: "icon", className: "h-8 w-8", children: _jsx(Plus, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-1", children: [_jsxs(Button, { variant: "quiet", className: "w-full justify-start font-normal text-sm text-muted-foreground hover:text-foreground", children: [_jsx(MessageSquare, { className: "mr-2 h-4 w-4" }), " E-commerce Data Model"] }), _jsxs(Button, { variant: "quiet", className: "w-full justify-start font-normal text-sm text-muted-foreground hover:text-foreground", children: [_jsx(MessageSquare, { className: "mr-2 h-4 w-4" }), " Fix Next.js Hydration Error"] })] }), _jsx("div", { className: "p-2 border-t border-border", children: _jsxs(Button, { variant: "quiet", className: "w-full justify-start text-sm", children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), " Settings"] }) })] }), _jsxs("div", { className: "flex flex-1 flex-col bg-background", children: [_jsxs("div", { className: "flex h-14 items-center border-b border-border px-4", children: [_jsx(Button, { variant: "quiet", size: "icon", className: "h-8 w-8 mr-2 md:hidden", onClick: () => setSidebarOpen(!sidebarOpen), children: _jsx(Menu, { className: "h-4 w-4" }) }), _jsx("span", { className: "font-medium text-sm", children: "New Chat" })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-4 md:p-6 space-y-6", children: messages.map((m, i) => (_jsx("div", { className: cx("flex w-full", m.role === "user" ? "justify-end" : "justify-start"), children: _jsx("div", { className: cx("max-w-[80%] rounded-2xl px-5 py-3 text-sm", m.role === "user"
|
|
21
|
+
? "bg-primary text-primary-foreground"
|
|
22
|
+
: "bg-muted/50 text-foreground border border-border/50"), children: m.role === "assistant" && i === messages.length - 1 ? (_jsx(TokenStream, { content: m.content, speed: 20 })) : (_jsx("span", { className: "whitespace-pre-wrap", children: m.content })) }) }, i))) }), _jsx("div", { className: "p-4 md:p-6 pt-0", children: _jsxs("div", { className: "mx-auto max-w-3xl", children: [_jsx(PromptInput, { onSubmit: handleSubmit }), _jsx("div", { className: "mt-2 text-center text-xs text-muted-foreground", children: "AI can make mistakes. Verify important information." })] }) })] })] }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface PromptInputProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, "onSubmit"> {
|
|
3
|
+
onValueSubmit?: (value: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare const PromptInput: React.ForwardRefExoticComponent<PromptInputProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Paperclip, ArrowUp } from "lucide-react";
|
|
5
|
+
import { cx } from "@/lib/cx";
|
|
6
|
+
import { Button } from "@/components/core/button";
|
|
7
|
+
export const PromptInput = React.forwardRef(({ className, onValueSubmit, ...props }, ref) => {
|
|
8
|
+
const internalRef = React.useRef(null);
|
|
9
|
+
const [value, setValue] = React.useState("");
|
|
10
|
+
const handleInput = (e) => {
|
|
11
|
+
setValue(e.target.value);
|
|
12
|
+
if (internalRef.current) {
|
|
13
|
+
internalRef.current.style.height = "auto";
|
|
14
|
+
internalRef.current.style.height = `${internalRef.current.scrollHeight}px`;
|
|
15
|
+
}
|
|
16
|
+
if (props.onChange)
|
|
17
|
+
props.onChange(e);
|
|
18
|
+
};
|
|
19
|
+
const handleKeyDown = (e) => {
|
|
20
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
if (value.trim() && onValueSubmit) {
|
|
23
|
+
onValueSubmit(value);
|
|
24
|
+
setValue("");
|
|
25
|
+
if (internalRef.current)
|
|
26
|
+
internalRef.current.style.height = "auto";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (props.onKeyDown)
|
|
30
|
+
props.onKeyDown(e);
|
|
31
|
+
};
|
|
32
|
+
return (_jsxs("div", { className: cx("relative flex w-full flex-col rounded-xl border border-border bg-card shadow-sm transition-colors focus-within:border-primary/50 focus-within:ring-1 focus-within:ring-primary/50", className), children: [_jsx("textarea", { ref: (node) => {
|
|
33
|
+
internalRef.current = node;
|
|
34
|
+
if (typeof ref === "function")
|
|
35
|
+
ref(node);
|
|
36
|
+
else if (ref)
|
|
37
|
+
ref.current = node;
|
|
38
|
+
}, value: value, onChange: handleInput, onKeyDown: handleKeyDown, rows: 1, placeholder: "Send a message...", className: "max-h-64 min-h-[56px] w-full resize-none bg-transparent px-4 py-4 pr-24 text-sm text-foreground outline-none placeholder:text-muted-foreground", ...props }), _jsxs("div", { className: "absolute bottom-2 right-2 flex items-center gap-1", children: [_jsxs(Button, { variant: "quiet", size: "icon", className: "h-8 w-8 rounded-lg text-muted-foreground hover:text-foreground", children: [_jsx(Paperclip, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Attach file" })] }), _jsxs(Button, { variant: value.trim() ? "solid" : "soft", size: "icon", className: "h-8 w-8 rounded-lg transition-colors", disabled: !value.trim(), onClick: () => {
|
|
39
|
+
if (value.trim() && onValueSubmit) {
|
|
40
|
+
onValueSubmit(value);
|
|
41
|
+
setValue("");
|
|
42
|
+
if (internalRef.current)
|
|
43
|
+
internalRef.current.style.height = "auto";
|
|
44
|
+
}
|
|
45
|
+
}, children: [_jsx(ArrowUp, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Send message" })] })] })] }));
|
|
46
|
+
});
|
|
47
|
+
PromptInput.displayName = "PromptInput";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { BlockManifest } from "../types";
|
|
3
|
+
export interface RegistryCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
block: BlockManifest;
|
|
5
|
+
}
|
|
6
|
+
export declare function RegistryCard({ block, className, ...props }: RegistryCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import { Terminal, Zap, ArrowRight, Lock } from "lucide-react";
|
|
4
|
+
import { Badge } from "@/components/core/badge";
|
|
5
|
+
import { cx } from "@/lib/cx";
|
|
6
|
+
import { CopyButton } from "@/components/core/copy-button";
|
|
7
|
+
/** Intentional fallback for blocks without a generated preview asset. */
|
|
8
|
+
function BlockPreviewFallback({ slug }) {
|
|
9
|
+
return (_jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-3 bg-surface-2", children: [_jsxs("div", { className: "w-32 h-20 rounded-lg border border-border-soft bg-surface flex flex-col gap-2 p-3", children: [_jsx("div", { className: "h-2 w-3/4 rounded-sm bg-border-strong/60" }), _jsx("div", { className: "h-2 w-1/2 rounded-sm bg-border-strong/40" }), _jsx("div", { className: "mt-auto h-5 w-full rounded-md bg-border-strong/30" })] }), _jsxs("span", { className: "text-[10px] font-mono text-muted-foreground/60", children: [slug, ".tsx"] })] }));
|
|
10
|
+
}
|
|
11
|
+
export function RegistryCard({ block, className, ...props }) {
|
|
12
|
+
const { title, slug, description, category, status, previewPath, difficulty, frameworks, dependencies, promptReady, version, licenseRequired } = block;
|
|
13
|
+
const isGated = licenseRequired || status === "pro" || status === "locked";
|
|
14
|
+
return (_jsxs("div", { className: cx("group flex flex-col overflow-hidden rounded-xl border border-border bg-surface text-card-foreground transition-all hover:border-border-strong", className), ...props, children: [_jsxs(Link, { href: `/blocks/${slug}`, className: "block relative aspect-video w-full overflow-hidden border-b border-border bg-surface-2 outline-none focus-visible:ring-2 focus-visible:ring-border-strong", children: [previewPath ? (_jsx("img", { src: previewPath, alt: `${title} preview`, className: "object-contain w-full h-full p-3" })) : (_jsx(BlockPreviewFallback, { slug: slug })), _jsxs("div", { className: "absolute top-3 right-3 flex gap-1.5", children: [isGated && (_jsxs(Badge, { variant: "signal", className: "bg-surface/80 backdrop-blur-sm uppercase text-[10px] tracking-wider font-mono flex items-center gap-1", children: [_jsx(Lock, { className: "h-2.5 w-2.5" }), " Pro"] })), status === "new" && !isGated && (_jsx(Badge, { variant: "new", className: "bg-surface/80 backdrop-blur-sm uppercase text-[10px] tracking-wider", children: "New" })), promptReady && (_jsxs(Badge, { variant: "neutral", className: "bg-surface/80 backdrop-blur-sm text-[10px] font-mono hidden group-hover:flex items-center gap-1", children: [_jsx(Zap, { className: "h-2.5 w-2.5" }), " Prompt Ready"] }))] })] }), _jsxs("div", { className: "flex flex-1 flex-col p-4", children: [_jsx(Link, { href: `/blocks/${slug}`, className: "outline-none focus-visible:underline", children: _jsx("h3", { className: "font-semibold text-sm leading-tight tracking-tight text-foreground group-hover:text-primary transition-colors", children: title }) }), _jsx("p", { className: "text-xs text-muted-foreground line-clamp-1 mt-1", children: description }), _jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 mt-4 text-[10px] font-mono text-muted-foreground", children: [_jsxs("span", { className: "text-border-strong", children: ["v", version] }), _jsx("span", { className: "text-border-strong", children: "\u00B7" }), _jsx("span", { children: category }), _jsx("span", { className: "text-border-strong", children: "\u00B7" }), _jsx("span", { children: difficulty }), _jsx("span", { className: "text-border-strong", children: "\u00B7" }), _jsx("span", { children: frameworks?.[0] || "react" }), _jsx("span", { className: "text-border-strong", children: "\u00B7" }), _jsxs("span", { children: [dependencies?.length ?? 0, " deps"] })] }), _jsxs("div", { className: "mt-4 pt-4 border-t border-border flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 bg-surface-2 border border-border rounded-md px-2.5 py-1.5 min-w-0 flex-1 max-w-[210px] group/cmd cursor-text", children: [_jsx(Terminal, { className: "h-3 w-3 text-muted-foreground flex-shrink-0" }), _jsxs("code", { className: "text-[10px] font-mono text-muted-foreground truncate flex-1", children: ["floyka add ", slug] }), _jsx(CopyButton, { value: `pnpm dlx floyka add ${slug}`, className: "h-5 w-5 opacity-0 group-hover/cmd:opacity-100 transition-opacity flex-shrink-0" })] }), _jsxs(Link, { href: `/blocks/${slug}`, className: "text-xs font-medium text-foreground flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-all duration-200 ease-out translate-x-1 group-hover:translate-x-0 flex-shrink-0", children: ["View ", _jsx(ArrowRight, { className: "h-3 w-3" })] })] })] })] }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BlockManifest } from "../types";
|
|
2
|
+
export interface RegistryExplorerProps {
|
|
3
|
+
initialBlocks: (BlockManifest & {
|
|
4
|
+
name?: string;
|
|
5
|
+
previewThumbnail?: string;
|
|
6
|
+
})[];
|
|
7
|
+
}
|
|
8
|
+
export declare function RegistryExplorer({ initialBlocks }: RegistryExplorerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Search, Check, Command } from "lucide-react";
|
|
5
|
+
import { Input } from "@/components/core/input";
|
|
6
|
+
import { cx } from "@/lib/cx";
|
|
7
|
+
import { RegistryCard } from "./registry-card";
|
|
8
|
+
export function RegistryExplorer({ initialBlocks }) {
|
|
9
|
+
const [search, setSearch] = React.useState("");
|
|
10
|
+
const [activeCategory, setActiveCategory] = React.useState("All");
|
|
11
|
+
const [activeDifficulty, setActiveDifficulty] = React.useState("All");
|
|
12
|
+
const [activeStatus, setActiveStatus] = React.useState("All");
|
|
13
|
+
const categories = ["All", ...Array.from(new Set(initialBlocks.map(b => b.category)))];
|
|
14
|
+
const difficulties = ["All", "beginner", "intermediate", "advanced"];
|
|
15
|
+
const statuses = ["All", "free", "pro", "new"];
|
|
16
|
+
const filteredBlocks = React.useMemo(() => {
|
|
17
|
+
return initialBlocks.filter((block) => {
|
|
18
|
+
const matchesSearch = block.title.toLowerCase().includes(search.toLowerCase()) ||
|
|
19
|
+
block.slug.toLowerCase().includes(search.toLowerCase()) ||
|
|
20
|
+
block.description.toLowerCase().includes(search.toLowerCase());
|
|
21
|
+
const matchesCategory = activeCategory === "All" || block.category === activeCategory;
|
|
22
|
+
const matchesDifficulty = activeDifficulty === "All" || block.difficulty === activeDifficulty;
|
|
23
|
+
const matchesStatus = activeStatus === "All" || block.status === activeStatus;
|
|
24
|
+
return matchesSearch && matchesCategory && matchesDifficulty && matchesStatus;
|
|
25
|
+
});
|
|
26
|
+
}, [initialBlocks, search, activeCategory, activeDifficulty, activeStatus]);
|
|
27
|
+
return (_jsxs("div", { className: "flex flex-col md:flex-row w-full max-w-[1400px] mx-auto px-6 py-12 gap-10", children: [_jsxs("aside", { className: "w-full md:w-64 flex-shrink-0 flex flex-col gap-8", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground px-2", children: "Registry Search" }), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" }), _jsx(Input, { type: "text", placeholder: "Search blocks...", value: search, onChange: (e) => setSearch(e.target.value), className: "pl-9 bg-surface-2 border-border h-9 text-sm" }), _jsx("div", { className: "absolute right-2 top-2 text-[10px] text-muted-foreground font-mono bg-surface border border-border px-1.5 py-0.5 rounded", children: "\u2318K" })] })] }), _jsx(FilterGroup, { title: "Categories", items: categories, activeItem: activeCategory, onChange: setActiveCategory }), _jsx(FilterGroup, { title: "Difficulty", items: difficulties, activeItem: activeDifficulty, onChange: setActiveDifficulty }), _jsx(FilterGroup, { title: "Status", items: statuses, activeItem: activeStatus, onChange: setActiveStatus })] }), _jsxs("main", { className: "flex-1 flex flex-col gap-6", children: [_jsx("div", { className: "flex items-center justify-between border-b border-border pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: "Blocks Registry" }), _jsxs("span", { className: "text-xs font-mono bg-surface-2 text-muted-foreground px-2 py-0.5 rounded-full border border-border", children: [filteredBlocks.length, " items"] })] }) }), filteredBlocks.length > 0 ? (_jsx("div", { className: "grid gap-6 grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3", children: filteredBlocks.map((block) => (_jsx(RegistryCard, { block: block }, block.slug))) })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-24 text-center border border-dashed border-border rounded-xl", children: [_jsx(Command, { className: "h-8 w-8 text-muted-foreground mb-4 opacity-50" }), _jsx("h3", { className: "text-lg font-medium", children: "No blocks found" }), _jsx("p", { className: "text-sm text-muted-foreground mt-1 max-w-sm", children: "We couldn't find any blocks matching your current filters. Try adjusting your search or clearing filters." }), _jsx("button", { onClick: () => {
|
|
28
|
+
setSearch("");
|
|
29
|
+
setActiveCategory("All");
|
|
30
|
+
setActiveDifficulty("All");
|
|
31
|
+
setActiveStatus("All");
|
|
32
|
+
}, className: "mt-6 text-sm text-foreground font-medium underline underline-offset-4 decoration-border-strong hover:decoration-foreground", children: "Clear all filters" })] }))] })] }));
|
|
33
|
+
}
|
|
34
|
+
function FilterGroup({ title, items, activeItem, onChange }) {
|
|
35
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-xs font-medium text-muted-foreground px-2 uppercase tracking-wider", children: title }), _jsx("div", { className: "flex flex-col gap-0.5", children: items.map((item) => (_jsxs("button", { onClick: () => onChange(item), className: cx("flex items-center justify-between px-2 py-1.5 text-sm rounded-md transition-colors text-left", activeItem === item
|
|
36
|
+
? "bg-surface-2 text-foreground font-medium"
|
|
37
|
+
: "text-muted-foreground hover:bg-surface-2/50 hover:text-foreground"), children: [_jsx("span", { className: "capitalize", children: item }), activeItem === item && _jsx(Check, { className: "h-3.5 w-3.5 text-foreground" })] }, item))) })] }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface TokenStreamProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
content: string;
|
|
4
|
+
speed?: number;
|
|
5
|
+
onComplete?: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function TokenStream({ content, speed, onComplete, className, ...props }: TokenStreamProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cx } from "@/lib/cx";
|
|
5
|
+
export function TokenStream({ content, speed = 15, onComplete, className, ...props }) {
|
|
6
|
+
const [displayedContent, setDisplayedContent] = React.useState("");
|
|
7
|
+
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
if (currentIndex < content.length) {
|
|
10
|
+
const timeout = setTimeout(() => {
|
|
11
|
+
setDisplayedContent((prev) => prev + content[currentIndex]);
|
|
12
|
+
setCurrentIndex((prev) => prev + 1);
|
|
13
|
+
}, speed);
|
|
14
|
+
return () => clearTimeout(timeout);
|
|
15
|
+
}
|
|
16
|
+
else if (onComplete) {
|
|
17
|
+
onComplete();
|
|
18
|
+
}
|
|
19
|
+
}, [content, currentIndex, speed, onComplete]);
|
|
20
|
+
return (_jsxs("div", { className: cx("relative inline-block", className), ...props, children: [_jsx("span", { className: "whitespace-pre-wrap", children: displayedContent }), currentIndex < content.length && (_jsx("span", { className: "ml-1 inline-block h-4 w-1 animate-pulse bg-primary align-middle" }))] }));
|
|
21
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Data and type exports — compiled by tsc into dist/
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
__exportStar(require("./manifests"), exports);
|
|
20
|
+
// UI component exports — consumed directly by Next.js via transpilePackages.
|
|
21
|
+
// These are NOT compiled by tsc (they import from web app internals).
|
|
22
|
+
// Import paths for UI: "@stampui/blocks/src/components/registry-card"
|
|
23
|
+
// or via the web app's tsconfig path alias "@stampui/blocks" -> src/index.ts
|