shapes-ui 0.1.1
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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.cta.json +12 -0
- package/.github/workflows/release.yml +44 -0
- package/.oxfmtrc.json +21 -0
- package/.oxlintrc.json +40 -0
- package/.vscode/settings.json +11 -0
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/content/components/accordion.mdx +41 -0
- package/content/components/alert-dialog.mdx +25 -0
- package/content/components/alert.mdx +53 -0
- package/content/components/badge.mdx +27 -0
- package/content/components/button.mdx +55 -0
- package/content-collections.ts +67 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +15255 -0
- package/dist/client/.assetsignore +2 -0
- package/dist/server/.vite/manifest.json +2435 -0
- package/examples/__index.tsx +201 -0
- package/examples/accordion-demo.tsx +30 -0
- package/examples/accordion-icon.tsx +40 -0
- package/examples/accordion-multiple.tsx +27 -0
- package/examples/accordion-small.tsx +30 -0
- package/examples/accordion-surface.tsx +30 -0
- package/examples/alert-action.tsx +18 -0
- package/examples/alert-demo.tsx +10 -0
- package/examples/alert-description.tsx +16 -0
- package/examples/alert-destructive.tsx +13 -0
- package/examples/alert-dialog-demo.tsx +33 -0
- package/examples/alert-dialog-destructive.tsx +33 -0
- package/examples/alert-dialog-icon.tsx +38 -0
- package/examples/alert-info.tsx +13 -0
- package/examples/alert-link.tsx +21 -0
- package/examples/alert-success.tsx +13 -0
- package/examples/alert-title.tsx +12 -0
- package/examples/alert-warning.tsx +13 -0
- package/examples/badge-demo.tsx +5 -0
- package/examples/badge-status-icon.tsx +26 -0
- package/examples/badge-status.tsx +12 -0
- package/examples/badge-variants.tsx +12 -0
- package/examples/button-default.tsx +15 -0
- package/examples/button-demo.tsx +14 -0
- package/examples/button-destructive.tsx +15 -0
- package/examples/button-ghost.tsx +15 -0
- package/examples/button-info.tsx +15 -0
- package/examples/button-link.tsx +15 -0
- package/examples/button-loading.tsx +14 -0
- package/examples/button-outline.tsx +15 -0
- package/examples/button-sizes.tsx +34 -0
- package/examples/button-success.tsx +15 -0
- package/examples/button-warning.tsx +15 -0
- package/package.json +81 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/circuit-board.svg +1 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +3 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/r/accordion.json +16 -0
- package/public/r/alert-dialog.json +17 -0
- package/public/r/alert.json +15 -0
- package/public/r/badge.json +15 -0
- package/public/r/button.json +16 -0
- package/public/r/index.json +7 -0
- package/public/robots.txt +3 -0
- package/public/shps_black.png +0 -0
- package/public/shps_black.svg +3 -0
- package/public/shps_white.png +0 -0
- package/public/shps_white.svg +3 -0
- package/scripts/generate-examples.mts +118 -0
- package/scripts/generate-registry.mts +129 -0
- package/src/commands/add.ts +125 -0
- package/src/commands/cli.ts +27 -0
- package/src/commands/init.ts +128 -0
- package/src/components/docs/docs-button.tsx +60 -0
- package/src/components/docs/layout/circuit-board.tsx +22 -0
- package/src/components/docs/layout/footer.tsx +11 -0
- package/src/components/docs/layout/header.tsx +49 -0
- package/src/components/docs/layout/mobile-menu.tsx +86 -0
- package/src/components/docs/layout/nav-list.tsx +43 -0
- package/src/components/docs/layout/page-header.tsx +33 -0
- package/src/components/docs/layout/split-layout.tsx +21 -0
- package/src/components/docs/layout/suspense-fallback.tsx +12 -0
- package/src/components/docs/markdown/components.tsx +324 -0
- package/src/components/docs/markdown/installation-block.tsx +146 -0
- package/src/components/docs/markdown/render-preview.tsx +152 -0
- package/src/components/docs/theme-provider.tsx +48 -0
- package/src/components/ui/accordion.tsx +83 -0
- package/src/components/ui/alert-dialog.tsx +162 -0
- package/src/components/ui/alert.tsx +72 -0
- package/src/components/ui/badge.tsx +34 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/lib/utils.ts +6 -0
- package/src/routeTree.gen.ts +131 -0
- package/src/router.tsx +17 -0
- package/src/routes/__root.tsx +72 -0
- package/src/routes/components.$slug.tsx +62 -0
- package/src/routes/components.index.tsx +55 -0
- package/src/routes/components.tsx +15 -0
- package/src/routes/index.tsx +16 -0
- package/src/styles/globals.css +66 -0
- package/src/styles/styles.css +113 -0
- package/src/types/registry-item.ts +13 -0
- package/src/utils/cli-utils.ts +46 -0
- package/src/utils/package-manager.ts +27 -0
- package/src/utils/schema.ts +25 -0
- package/tests/generate-registry.test.ts +60 -0
- package/tsconfig.json +29 -0
- package/tsup.config.ts +11 -0
- package/vite.config.ts +31 -0
- package/vitest.config.ts +8 -0
- package/wrangler.jsonc +7 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
// noinspection JSUnusedGlobalSymbols
|
|
6
|
+
|
|
7
|
+
// This file was automatically generated by TanStack Router.
|
|
8
|
+
// You should NOT make any changes in this file as it will be overwritten.
|
|
9
|
+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
10
|
+
|
|
11
|
+
import { Route as rootRouteImport } from './routes/__root'
|
|
12
|
+
import { Route as ComponentsRouteImport } from './routes/components'
|
|
13
|
+
import { Route as IndexRouteImport } from './routes/index'
|
|
14
|
+
import { Route as ComponentsIndexRouteImport } from './routes/components.index'
|
|
15
|
+
import { Route as ComponentsSlugRouteImport } from './routes/components.$slug'
|
|
16
|
+
|
|
17
|
+
const ComponentsRoute = ComponentsRouteImport.update({
|
|
18
|
+
id: '/components',
|
|
19
|
+
path: '/components',
|
|
20
|
+
getParentRoute: () => rootRouteImport,
|
|
21
|
+
} as any)
|
|
22
|
+
const IndexRoute = IndexRouteImport.update({
|
|
23
|
+
id: '/',
|
|
24
|
+
path: '/',
|
|
25
|
+
getParentRoute: () => rootRouteImport,
|
|
26
|
+
} as any)
|
|
27
|
+
const ComponentsIndexRoute = ComponentsIndexRouteImport.update({
|
|
28
|
+
id: '/',
|
|
29
|
+
path: '/',
|
|
30
|
+
getParentRoute: () => ComponentsRoute,
|
|
31
|
+
} as any)
|
|
32
|
+
const ComponentsSlugRoute = ComponentsSlugRouteImport.update({
|
|
33
|
+
id: '/$slug',
|
|
34
|
+
path: '/$slug',
|
|
35
|
+
getParentRoute: () => ComponentsRoute,
|
|
36
|
+
} as any)
|
|
37
|
+
|
|
38
|
+
export interface FileRoutesByFullPath {
|
|
39
|
+
'/': typeof IndexRoute
|
|
40
|
+
'/components': typeof ComponentsRouteWithChildren
|
|
41
|
+
'/components/$slug': typeof ComponentsSlugRoute
|
|
42
|
+
'/components/': typeof ComponentsIndexRoute
|
|
43
|
+
}
|
|
44
|
+
export interface FileRoutesByTo {
|
|
45
|
+
'/': typeof IndexRoute
|
|
46
|
+
'/components/$slug': typeof ComponentsSlugRoute
|
|
47
|
+
'/components': typeof ComponentsIndexRoute
|
|
48
|
+
}
|
|
49
|
+
export interface FileRoutesById {
|
|
50
|
+
__root__: typeof rootRouteImport
|
|
51
|
+
'/': typeof IndexRoute
|
|
52
|
+
'/components': typeof ComponentsRouteWithChildren
|
|
53
|
+
'/components/$slug': typeof ComponentsSlugRoute
|
|
54
|
+
'/components/': typeof ComponentsIndexRoute
|
|
55
|
+
}
|
|
56
|
+
export interface FileRouteTypes {
|
|
57
|
+
fileRoutesByFullPath: FileRoutesByFullPath
|
|
58
|
+
fullPaths: '/' | '/components' | '/components/$slug' | '/components/'
|
|
59
|
+
fileRoutesByTo: FileRoutesByTo
|
|
60
|
+
to: '/' | '/components/$slug' | '/components'
|
|
61
|
+
id: '__root__' | '/' | '/components' | '/components/$slug' | '/components/'
|
|
62
|
+
fileRoutesById: FileRoutesById
|
|
63
|
+
}
|
|
64
|
+
export interface RootRouteChildren {
|
|
65
|
+
IndexRoute: typeof IndexRoute
|
|
66
|
+
ComponentsRoute: typeof ComponentsRouteWithChildren
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
declare module '@tanstack/react-router' {
|
|
70
|
+
interface FileRoutesByPath {
|
|
71
|
+
'/components': {
|
|
72
|
+
id: '/components'
|
|
73
|
+
path: '/components'
|
|
74
|
+
fullPath: '/components'
|
|
75
|
+
preLoaderRoute: typeof ComponentsRouteImport
|
|
76
|
+
parentRoute: typeof rootRouteImport
|
|
77
|
+
}
|
|
78
|
+
'/': {
|
|
79
|
+
id: '/'
|
|
80
|
+
path: '/'
|
|
81
|
+
fullPath: '/'
|
|
82
|
+
preLoaderRoute: typeof IndexRouteImport
|
|
83
|
+
parentRoute: typeof rootRouteImport
|
|
84
|
+
}
|
|
85
|
+
'/components/': {
|
|
86
|
+
id: '/components/'
|
|
87
|
+
path: '/'
|
|
88
|
+
fullPath: '/components/'
|
|
89
|
+
preLoaderRoute: typeof ComponentsIndexRouteImport
|
|
90
|
+
parentRoute: typeof ComponentsRoute
|
|
91
|
+
}
|
|
92
|
+
'/components/$slug': {
|
|
93
|
+
id: '/components/$slug'
|
|
94
|
+
path: '/$slug'
|
|
95
|
+
fullPath: '/components/$slug'
|
|
96
|
+
preLoaderRoute: typeof ComponentsSlugRouteImport
|
|
97
|
+
parentRoute: typeof ComponentsRoute
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface ComponentsRouteChildren {
|
|
103
|
+
ComponentsSlugRoute: typeof ComponentsSlugRoute
|
|
104
|
+
ComponentsIndexRoute: typeof ComponentsIndexRoute
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const ComponentsRouteChildren: ComponentsRouteChildren = {
|
|
108
|
+
ComponentsSlugRoute: ComponentsSlugRoute,
|
|
109
|
+
ComponentsIndexRoute: ComponentsIndexRoute,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ComponentsRouteWithChildren = ComponentsRoute._addFileChildren(
|
|
113
|
+
ComponentsRouteChildren,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
const rootRouteChildren: RootRouteChildren = {
|
|
117
|
+
IndexRoute: IndexRoute,
|
|
118
|
+
ComponentsRoute: ComponentsRouteWithChildren,
|
|
119
|
+
}
|
|
120
|
+
export const routeTree = rootRouteImport
|
|
121
|
+
._addFileChildren(rootRouteChildren)
|
|
122
|
+
._addFileTypes<FileRouteTypes>()
|
|
123
|
+
|
|
124
|
+
import type { getRouter } from './router.tsx'
|
|
125
|
+
import type { createStart } from '@tanstack/react-start'
|
|
126
|
+
declare module '@tanstack/react-start' {
|
|
127
|
+
interface Register {
|
|
128
|
+
ssr: true
|
|
129
|
+
router: Awaited<ReturnType<typeof getRouter>>
|
|
130
|
+
}
|
|
131
|
+
}
|
package/src/router.tsx
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createRouter } from "@tanstack/react-router";
|
|
2
|
+
|
|
3
|
+
// Import the generated route tree
|
|
4
|
+
import { routeTree } from "./routeTree.gen";
|
|
5
|
+
|
|
6
|
+
// Create a new router instance
|
|
7
|
+
export const getRouter = () => {
|
|
8
|
+
const router = createRouter({
|
|
9
|
+
routeTree,
|
|
10
|
+
context: {},
|
|
11
|
+
|
|
12
|
+
scrollRestoration: true,
|
|
13
|
+
defaultPreloadStaleTime: 0,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return router;
|
|
17
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { TanStackDevtools } from "@tanstack/react-devtools";
|
|
2
|
+
import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router";
|
|
3
|
+
import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools";
|
|
4
|
+
import { Suspense } from "react";
|
|
5
|
+
|
|
6
|
+
import { Footer } from "@/components/docs/layout/footer";
|
|
7
|
+
import { Header } from "@/components/docs/layout/header";
|
|
8
|
+
import { SuspenseFallback } from "@/components/docs/layout/suspense-fallback";
|
|
9
|
+
import { ThemeProvider } from "@/components/docs/theme-provider";
|
|
10
|
+
import globalCss from "@/styles/globals.css?url";
|
|
11
|
+
|
|
12
|
+
export const Route = createRootRoute({
|
|
13
|
+
head: () => ({
|
|
14
|
+
meta: [
|
|
15
|
+
{
|
|
16
|
+
charSet: "utf-8",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "viewport",
|
|
20
|
+
content: "width=device-width, initial-scale=1",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
title: "Shapes UI - The better way to build web apps",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
links: [
|
|
27
|
+
{
|
|
28
|
+
rel: "stylesheet",
|
|
29
|
+
href: globalCss,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
rel: "icon",
|
|
33
|
+
href: "/favicon.ico",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}),
|
|
37
|
+
|
|
38
|
+
shellComponent: RootDocument,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
42
|
+
return (
|
|
43
|
+
<Suspense fallback={<SuspenseFallback className=" h-dvh" />}>
|
|
44
|
+
<ThemeProvider>
|
|
45
|
+
<html lang="en">
|
|
46
|
+
<head>
|
|
47
|
+
<HeadContent />
|
|
48
|
+
</head>
|
|
49
|
+
<body className="flex h-dvh flex-col">
|
|
50
|
+
<Header />
|
|
51
|
+
<main className=" container mx-auto flex flex-1 overflow-hidden border-x">
|
|
52
|
+
{children}
|
|
53
|
+
</main>
|
|
54
|
+
<Footer />
|
|
55
|
+
<TanStackDevtools
|
|
56
|
+
config={{
|
|
57
|
+
position: "bottom-right",
|
|
58
|
+
}}
|
|
59
|
+
plugins={[
|
|
60
|
+
{
|
|
61
|
+
name: "Tanstack Router",
|
|
62
|
+
render: <TanStackRouterDevtoolsPanel />,
|
|
63
|
+
},
|
|
64
|
+
]}
|
|
65
|
+
/>
|
|
66
|
+
<Scripts />
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
69
|
+
</ThemeProvider>
|
|
70
|
+
</Suspense>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { MDXContent } from "@content-collections/mdx/react";
|
|
2
|
+
import { createFileRoute, notFound } from "@tanstack/react-router";
|
|
3
|
+
import { allComponents } from "content-collections";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
|
|
6
|
+
import { PageHeader } from "@/components/docs/layout/page-header";
|
|
7
|
+
import { mdxComponents } from "@/components/docs/markdown/components";
|
|
8
|
+
import { RenderPreview } from "@/components/docs/markdown/render-preview";
|
|
9
|
+
|
|
10
|
+
export const Route = createFileRoute("/components/$slug")({
|
|
11
|
+
loader: ({ params }) => {
|
|
12
|
+
const { slug } = params;
|
|
13
|
+
const component = (allComponents as any[]).find((c) => c.slug === slug);
|
|
14
|
+
|
|
15
|
+
if (!component) {
|
|
16
|
+
throw notFound();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return component;
|
|
20
|
+
},
|
|
21
|
+
head: ({ loaderData }) => ({
|
|
22
|
+
meta: [
|
|
23
|
+
{
|
|
24
|
+
charSet: "utf-8",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "viewport",
|
|
28
|
+
content: "width=device-width, initial-scale=1",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: `${loaderData?.title} - Shapes UI`,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
links: [
|
|
35
|
+
{
|
|
36
|
+
rel: "icon",
|
|
37
|
+
href: "/favicon.ico",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
}),
|
|
41
|
+
component: RouteComponent,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function RouteComponent() {
|
|
45
|
+
const component = Route.useLoaderData();
|
|
46
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setIsMounted(true);
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className=" flex flex-col gap-6 ">
|
|
54
|
+
<PageHeader title={component?.title} subtitle={component?.description} />
|
|
55
|
+
<div className="container mx-auto max-w-4xl min-w-0 p-6">
|
|
56
|
+
{isMounted ? (
|
|
57
|
+
<MDXContent code={component.mdx} components={{ ...mdxComponents, RenderPreview }} />
|
|
58
|
+
) : null}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createFileRoute, Link } from "@tanstack/react-router";
|
|
2
|
+
import { allComponents } from "content-collections";
|
|
3
|
+
|
|
4
|
+
import { PageHeader } from "@/components/docs/layout/page-header";
|
|
5
|
+
|
|
6
|
+
export const Route = createFileRoute("/components/")({
|
|
7
|
+
component: RouteComponent,
|
|
8
|
+
head: () => ({
|
|
9
|
+
meta: [
|
|
10
|
+
{
|
|
11
|
+
charSet: "utf-8",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "viewport",
|
|
15
|
+
content: "width=device-width, initial-scale=1",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: "All components - Shapes UI",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
links: [
|
|
22
|
+
{
|
|
23
|
+
rel: "icon",
|
|
24
|
+
href: "/favicon.ico?url",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function RouteComponent() {
|
|
31
|
+
return (
|
|
32
|
+
<div className="flex flex-col gap-6">
|
|
33
|
+
<PageHeader title="Components">
|
|
34
|
+
<p className=" text-sm text-muted-foreground">
|
|
35
|
+
List of all available components. We are working on adding more components.
|
|
36
|
+
</p>
|
|
37
|
+
</PageHeader>
|
|
38
|
+
|
|
39
|
+
<div className="mx-auto grid w-full max-w-5xl grid-cols-3 gap-2 p-6">
|
|
40
|
+
{[...allComponents]
|
|
41
|
+
.sort((a, b) => a.title.localeCompare(b.title))
|
|
42
|
+
.map((component) => (
|
|
43
|
+
<Link
|
|
44
|
+
key={component.slug}
|
|
45
|
+
to="/components/$slug"
|
|
46
|
+
params={{ slug: component.slug }}
|
|
47
|
+
className=" rounded border p-4 text-sm hover:bg-accent/40"
|
|
48
|
+
>
|
|
49
|
+
{component.title}
|
|
50
|
+
</Link>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createFileRoute, Outlet } from "@tanstack/react-router";
|
|
2
|
+
|
|
3
|
+
import { SplitLayout } from "@/components/docs/layout/split-layout";
|
|
4
|
+
|
|
5
|
+
export const Route = createFileRoute("/components")({
|
|
6
|
+
component: RouteComponent,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
function RouteComponent() {
|
|
10
|
+
return (
|
|
11
|
+
<SplitLayout>
|
|
12
|
+
<Outlet />
|
|
13
|
+
</SplitLayout>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
|
|
3
|
+
export const Route = createFileRoute("/")({ component: App });
|
|
4
|
+
|
|
5
|
+
function App() {
|
|
6
|
+
return (
|
|
7
|
+
<div className=" flex-1 ">
|
|
8
|
+
<div className=" container mx-auto flex h-full flex-col items-center justify-center gap-6 p-6">
|
|
9
|
+
<h1 className=" text-center text-4xl font-bold">Build better products. Faster.</h1>
|
|
10
|
+
<div className=" w-fit rounded border bg-accent px-2 py-1 leading-0 text-accent-foreground">
|
|
11
|
+
<span className=" font-mono text-xs uppercase">alpha coming soon</span>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Space+Grotesk:wght@300..700&display=swap");
|
|
2
|
+
|
|
3
|
+
@import "./styles.css";
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--shiki-light-bg: transparent;
|
|
7
|
+
--shiki-dark-bg: transparent;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.shiki,
|
|
11
|
+
.shiki code,
|
|
12
|
+
.shiki pre {
|
|
13
|
+
background-color: transparent !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.shiki {
|
|
17
|
+
margin: 0;
|
|
18
|
+
overflow-x: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.shiki,
|
|
22
|
+
.shiki span {
|
|
23
|
+
color: var(--shiki-light);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.dark .shiki,
|
|
27
|
+
.dark .shiki span {
|
|
28
|
+
color: var(--shiki-dark);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.line {
|
|
32
|
+
display: inline-block;
|
|
33
|
+
min-width: 100%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.line-number {
|
|
37
|
+
display: inline-block;
|
|
38
|
+
width: 1.5rem;
|
|
39
|
+
margin-right: 1rem;
|
|
40
|
+
text-align: right;
|
|
41
|
+
color: var(--muted-foreground);
|
|
42
|
+
user-select: none;
|
|
43
|
+
opacity: 0.5;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Right-to-left opacity mask for images and svgs */
|
|
47
|
+
.mask-rtl {
|
|
48
|
+
-webkit-mask-image: linear-gradient(
|
|
49
|
+
to left,
|
|
50
|
+
rgba(0, 0, 0, 1) 0%,
|
|
51
|
+
rgba(0, 0, 0, 1) 15%,
|
|
52
|
+
rgba(0, 0, 0, 0.85) 45%,
|
|
53
|
+
rgba(0, 0, 0, 0.45) 70%,
|
|
54
|
+
rgba(0, 0, 0, 0.1) 85%,
|
|
55
|
+
rgba(0, 0, 0, 0) 100%
|
|
56
|
+
);
|
|
57
|
+
mask-image: linear-gradient(
|
|
58
|
+
to left,
|
|
59
|
+
rgba(0, 0, 0, 1) 0%,
|
|
60
|
+
rgba(0, 0, 0, 1) 15%,
|
|
61
|
+
rgba(0, 0, 0, 0.85) 45%,
|
|
62
|
+
rgba(0, 0, 0, 0.45) 70%,
|
|
63
|
+
rgba(0, 0, 0, 0.1) 85%,
|
|
64
|
+
rgba(0, 0, 0, 0) 100%
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
@custom-variant dark (&: is(.dark *));
|
|
5
|
+
|
|
6
|
+
:root {
|
|
7
|
+
--background: oklch(1 0 0);
|
|
8
|
+
--foreground: oklch(0.145 0 0);
|
|
9
|
+
--card: oklch(1 0 0);
|
|
10
|
+
--card-foreground: oklch(0.145 0 0);
|
|
11
|
+
--popup: oklch(1 0 0);
|
|
12
|
+
--popup-foreground: oklch(0.145 0 0);
|
|
13
|
+
--primary: oklch(0.205 0 0);
|
|
14
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
15
|
+
--secondary: oklch(0.97 0 0);
|
|
16
|
+
--secondary-foreground: oklch(0.205 0 0);
|
|
17
|
+
--muted: oklch(0.97 0 0);
|
|
18
|
+
--muted-foreground: oklch(0.556 0 0);
|
|
19
|
+
--accent: oklch(0.97 0 0);
|
|
20
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
21
|
+
--destructive: oklch(57.7% 0.245 27.325);
|
|
22
|
+
--destructive-foreground: oklch(57.7% 0.245 27.325);
|
|
23
|
+
--success: oklch(56.4% 0.168 143.8);
|
|
24
|
+
--success-foreground: oklch(56.4% 0.168 143.8);
|
|
25
|
+
--warning: oklch(68.1% 0.15 59);
|
|
26
|
+
--warning-foreground: oklch(68.1% 0.15 59);
|
|
27
|
+
--info: oklch(60.9% 0.202 257.2);
|
|
28
|
+
--info-foreground: oklch(60.9% 0.202 257.2);
|
|
29
|
+
--border: oklch(0.922 0 0);
|
|
30
|
+
--input: oklch(0.922 0 0);
|
|
31
|
+
--ring: oklch(0.708 0 0);
|
|
32
|
+
--radius: 0.25rem;
|
|
33
|
+
--transform-origin: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.dark {
|
|
37
|
+
--background: oklch(0.145 0 0);
|
|
38
|
+
--foreground: oklch(0.985 0 0);
|
|
39
|
+
--card: oklch(0.145 0 0);
|
|
40
|
+
--card-foreground: oklch(0.985 0 0);
|
|
41
|
+
--popup: oklch(0.145 0 0);
|
|
42
|
+
--popup-foreground: oklch(0.985 0 0);
|
|
43
|
+
--primary: oklch(0.985 0 0);
|
|
44
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
45
|
+
--secondary: oklch(0.269 0 0);
|
|
46
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
47
|
+
--muted: oklch(0.269 0 0);
|
|
48
|
+
--muted-foreground: oklch(0.708 0 0);
|
|
49
|
+
--accent: oklch(0.269 0 0);
|
|
50
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
51
|
+
--destructive: oklch(39.6% 0.141 25.723);
|
|
52
|
+
--destructive-foreground: oklch(55.109% 0.20302 26.431);
|
|
53
|
+
--success: oklch(63.4% 0.188 142.8);
|
|
54
|
+
--success-foreground: oklch(75.202% 0.22616 142.706);
|
|
55
|
+
--warning: oklch(78.5% 0.162 64.8);
|
|
56
|
+
--warning-foreground: oklch(78.5% 0.162 64.8);
|
|
57
|
+
--info: oklch(70.1% 0.156 247.3);
|
|
58
|
+
--info-foreground: oklch(70.1% 0.156 247.3);
|
|
59
|
+
--border: oklch(0.269 0 0);
|
|
60
|
+
--input: oklch(0.269 0 0);
|
|
61
|
+
--ring: oklch(0.439 0 0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@layer base {
|
|
65
|
+
* {
|
|
66
|
+
@apply border-border box-border;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
body {
|
|
70
|
+
@apply relative isolate bg-background text-foreground;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@theme inline {
|
|
75
|
+
--font-sans: "Inter", sans-serif;
|
|
76
|
+
--font-heading: "Space Grotesk", sans-serif;
|
|
77
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
78
|
+
|
|
79
|
+
--color-background: var(--background);
|
|
80
|
+
--color-foreground: var(--foreground);
|
|
81
|
+
--color-card: var(--card);
|
|
82
|
+
--color-card-foreground: var(--card-foreground);
|
|
83
|
+
--color-popup: var(--popup);
|
|
84
|
+
--color-popup-foreground: var(--popup-foreground);
|
|
85
|
+
--color-primary: var(--primary);
|
|
86
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
87
|
+
--color-secondary: var(--secondary);
|
|
88
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
89
|
+
--color-muted: var(--muted);
|
|
90
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
91
|
+
--color-accent: var(--accent);
|
|
92
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
93
|
+
--color-destructive: var(--destructive);
|
|
94
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
95
|
+
--color-success: var(--success);
|
|
96
|
+
--color-success-foreground: var(--success-foreground);
|
|
97
|
+
--color-info: var(--info);
|
|
98
|
+
--color-info-foreground: var(--info-foreground);
|
|
99
|
+
--color-warning: var(--warning);
|
|
100
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
101
|
+
--color-border: var(--border);
|
|
102
|
+
--color-input: var(--input);
|
|
103
|
+
--color-ring: var(--ring);
|
|
104
|
+
|
|
105
|
+
/* Update radius if you want rounded corners */
|
|
106
|
+
--radius: var(--radius);
|
|
107
|
+
--radius-xs: calc(var(--radius) * 0.25);
|
|
108
|
+
--radius-sm: calc(var(--radius) * 0.5);
|
|
109
|
+
--radius-md: var(--radius); /* This is what '.rounded' usually targets */
|
|
110
|
+
--radius-lg: calc(var(--radius) * 1.5);
|
|
111
|
+
--radius-xl: calc(var(--radius) * 2);
|
|
112
|
+
--radius-2xl: calc(var(--radius) * 2.5);
|
|
113
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type RegistryItem = {
|
|
2
|
+
name: string;
|
|
3
|
+
type: "registry:ui" | "registry:hook" | "registry:recipe";
|
|
4
|
+
dependencies?: string[];
|
|
5
|
+
registryDependencies?: string[];
|
|
6
|
+
files: {
|
|
7
|
+
path: string;
|
|
8
|
+
content: string;
|
|
9
|
+
type: "registry:ui";
|
|
10
|
+
}[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type RegistryIndex = RegistryItem[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { cancel, isCancel } from "@clack/prompts";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
|
|
6
|
+
import { configSchema, type Config } from "@/utils/schema";
|
|
7
|
+
|
|
8
|
+
export function exitIfCancelled<T>(value: T): Exclude<T, symbol> {
|
|
9
|
+
if (isCancel(value)) {
|
|
10
|
+
cancel("Operation cancelled.");
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
return value as Exclude<T, symbol>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function getConfig(): Promise<Config | null> {
|
|
17
|
+
const configPath = path.join(process.cwd(), "shapes.json");
|
|
18
|
+
if (!fs.existsSync(configPath)) return null;
|
|
19
|
+
return configSchema.parse(await fs.readJSON(configPath));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function readPackageJson() {
|
|
23
|
+
const pkgPath = path.join(process.cwd(), "package.json");
|
|
24
|
+
if (!(await fs.pathExists(pkgPath))) return null;
|
|
25
|
+
return fs.readJSON(pkgPath);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getDepVersion(pkg: Record<string, any> | null, name: string) {
|
|
29
|
+
return pkg?.dependencies?.[name] ?? pkg?.devDependencies?.[name] ?? null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function parseMajor(version: string | null) {
|
|
33
|
+
if (!version) return null;
|
|
34
|
+
const match = version.match(/\d+/);
|
|
35
|
+
return match ? Number.parseInt(match[0], 10) : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function isTailwindV4Installed(pkg: Record<string, any> | null) {
|
|
39
|
+
const major = parseMajor(getDepVersion(pkg, "tailwindcss"));
|
|
40
|
+
return major === 4;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getMissingDeps(pkg: Record<string, any> | null, deps: string[]) {
|
|
44
|
+
if (!pkg) return deps;
|
|
45
|
+
return deps.filter((dep) => !pkg.dependencies?.[dep] && !pkg.devDependencies?.[dep]);
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { detect } from "detect-package-manager";
|
|
2
|
+
|
|
3
|
+
export async function getPackageManager() {
|
|
4
|
+
try {
|
|
5
|
+
return await detect();
|
|
6
|
+
} catch {
|
|
7
|
+
return "npm";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function getInstallCommand(deps: string[], dev = false) {
|
|
12
|
+
const pm = await getPackageManager();
|
|
13
|
+
|
|
14
|
+
if (pm === "yarn") {
|
|
15
|
+
return ["yarn", "add", ...(dev ? ["-D"] : []), ...deps];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (pm === "pnpm") {
|
|
19
|
+
return ["pnpm", "add", ...(dev ? ["-D"] : []), ...deps];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (pm === "bun") {
|
|
23
|
+
return ["bun", "add", ...(dev ? ["-d"] : []), ...deps];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return ["npm", "install", ...(dev ? ["--save-dev"] : []), ...deps];
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
4
|
+
|
|
5
|
+
export const configSchema = z.object({
|
|
6
|
+
$schema: z.string().optional(),
|
|
7
|
+
style: z.enum(["default", "brutalist", "minimal"]).default("default"),
|
|
8
|
+
tailwind: z.object({
|
|
9
|
+
config: z.string().optional(),
|
|
10
|
+
css: z.string().default("src/styles/globals.css"),
|
|
11
|
+
baseColor: z.string().default("zinc"),
|
|
12
|
+
}),
|
|
13
|
+
paths: z.object({
|
|
14
|
+
ui: z.string().default("./src/components/ui"),
|
|
15
|
+
lib: z.string().default("./src/lib"),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type Config = z.infer<typeof configSchema>;
|
|
20
|
+
|
|
21
|
+
export function generateSchemaJson() {
|
|
22
|
+
const jsonSchema = zodToJsonSchema(configSchema as any, "ShapesUIConfig");
|
|
23
|
+
fs.writeJSONSync("./public/schema.json", jsonSchema, { spaces: 2 });
|
|
24
|
+
console.log("✅ Schema generated at ./public/schema.json");
|
|
25
|
+
}
|