cronus-ui 0.6.2 → 0.6.3
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/README.md +2 -2
- package/dist/compose/gold-path.d.ts +2 -2
- package/dist/compose/gold-path.js +155 -21
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ Notes that match the commander surface:
|
|
|
49
49
|
`packages/cli/scripts/build-registry.ts` — each item carries its source, its npm
|
|
50
50
|
`dependencies`, and its `registryDependencies` (other components it imports),
|
|
51
51
|
derived by parsing imports.
|
|
52
|
-
- The default registry is pinned to the CLI package version (`v0.6.
|
|
52
|
+
- The default registry is pinned to the CLI package version (`v0.6.3` here), not
|
|
53
53
|
mutable `main`, so a published CLI reads the registry snapshot it was released
|
|
54
54
|
with. Use `-r, --registry ./registry` when testing local registry changes before
|
|
55
55
|
a release tag exists.
|
|
@@ -80,7 +80,7 @@ Notes that match the commander surface:
|
|
|
80
80
|
"lib": "lib",
|
|
81
81
|
"blocks": "components/blocks"
|
|
82
82
|
},
|
|
83
|
-
"registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.
|
|
83
|
+
"registry": "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.3/registry"
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -39,8 +39,8 @@ export declare function patchChromeSource(source: string, workspaceImport: strin
|
|
|
39
39
|
export declare function patchHomePageSource(source: string, itemsImport: string): string | undefined;
|
|
40
40
|
/**
|
|
41
41
|
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
42
|
-
* Overwrites lib/auth-adapter.ts always
|
|
43
|
-
*
|
|
42
|
+
* Overwrites lib/auth-adapter.ts and lib/items.ts always. Patches the shell
|
|
43
|
+
* home page only when compose wrote it this run.
|
|
44
44
|
*/
|
|
45
45
|
export declare function applyGoldPath(options: ApplyGoldPathOptions): Promise<ApplyGoldPathResult>;
|
|
46
46
|
//# sourceMappingURL=gold-path.d.ts.map
|
|
@@ -38,6 +38,7 @@ const ENV_VARS = {
|
|
|
38
38
|
};
|
|
39
39
|
const GITIGNORE_ENTRIES = ["*.db", "data/", "drizzle/"];
|
|
40
40
|
const DATABASE_URL_FALLBACK = "file:./data/app.db";
|
|
41
|
+
const TITLE_MAX = 200;
|
|
41
42
|
export function goldPathLayout(config) {
|
|
42
43
|
const libDir = posix(config.paths.lib);
|
|
43
44
|
const uiDir = posix(config.paths.ui);
|
|
@@ -432,37 +433,154 @@ export const config = {
|
|
|
432
433
|
};
|
|
433
434
|
`;
|
|
434
435
|
}
|
|
435
|
-
function
|
|
436
|
-
return `
|
|
436
|
+
function itemsActionsSource(authImport) {
|
|
437
|
+
return `"use server";
|
|
438
|
+
|
|
439
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
440
|
+
import { revalidatePath } from "next/cache";
|
|
437
441
|
import { headers } from "next/headers";
|
|
438
442
|
import { db } from "@/db";
|
|
439
443
|
import { items, member, organization } from "@/db/schema";
|
|
440
444
|
import { auth } from ${JSON.stringify(authImport)};
|
|
441
445
|
|
|
442
|
-
|
|
446
|
+
const TITLE_MAX = ${TITLE_MAX};
|
|
447
|
+
|
|
448
|
+
async function activeWorkspaceId(): Promise<string | null> {
|
|
443
449
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
444
|
-
|
|
445
|
-
if (!
|
|
446
|
-
|
|
450
|
+
const userId = session?.user?.id;
|
|
451
|
+
if (!userId) return null;
|
|
452
|
+
const hinted = session.session?.activeOrganizationId ?? null;
|
|
453
|
+
if (hinted) {
|
|
454
|
+
const [membership] = await db
|
|
447
455
|
.select({ organizationId: member.organizationId })
|
|
448
456
|
.from(member)
|
|
449
|
-
.where(eq(member.userId,
|
|
457
|
+
.where(and(eq(member.userId, userId), eq(member.organizationId, hinted)))
|
|
450
458
|
.limit(1);
|
|
451
|
-
|
|
459
|
+
if (membership?.organizationId) return membership.organizationId;
|
|
452
460
|
}
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
461
|
+
const [row] = await db
|
|
462
|
+
.select({ organizationId: member.organizationId })
|
|
463
|
+
.from(member)
|
|
464
|
+
.where(eq(member.userId, userId))
|
|
465
|
+
.limit(1);
|
|
466
|
+
return row?.organizationId ?? null;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export async function loadItems(): Promise<{
|
|
470
|
+
email: string;
|
|
471
|
+
workspace: string;
|
|
472
|
+
rows: { id: number; title: string }[];
|
|
473
|
+
}> {
|
|
474
|
+
const session = await auth.api.getSession({ headers: await headers() });
|
|
459
475
|
const email = session?.user?.email ?? "signed out";
|
|
460
|
-
const
|
|
476
|
+
const orgId = await activeWorkspaceId();
|
|
477
|
+
if (!orgId) return { email, workspace: "no workspace", rows: [] };
|
|
478
|
+
const [org] = await db.select().from(organization).where(eq(organization.id, orgId)).limit(1);
|
|
479
|
+
const rows = await db
|
|
480
|
+
.select({ id: items.id, title: items.title })
|
|
481
|
+
.from(items)
|
|
482
|
+
.where(eq(items.workspaceId, orgId))
|
|
483
|
+
.orderBy(desc(items.id));
|
|
484
|
+
return { email, workspace: org?.name ?? "no workspace", rows };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export async function createItem(formData: FormData) {
|
|
488
|
+
const orgId = await activeWorkspaceId();
|
|
489
|
+
if (!orgId) return;
|
|
490
|
+
const title = String(formData.get("title") ?? "")
|
|
491
|
+
.trim()
|
|
492
|
+
.slice(0, TITLE_MAX);
|
|
493
|
+
if (!title) return;
|
|
494
|
+
await db.insert(items).values({ title, workspaceId: orgId });
|
|
495
|
+
revalidatePath("/");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export async function deleteItem(formData: FormData) {
|
|
499
|
+
const orgId = await activeWorkspaceId();
|
|
500
|
+
if (!orgId) return;
|
|
501
|
+
const id = Number(formData.get("id"));
|
|
502
|
+
if (!Number.isInteger(id) || id < 1) return;
|
|
503
|
+
await db.delete(items).where(and(eq(items.id, id), eq(items.workspaceId, orgId)));
|
|
504
|
+
revalidatePath("/");
|
|
505
|
+
}
|
|
506
|
+
`;
|
|
507
|
+
}
|
|
508
|
+
function itemsPanelSource(actionsImport, viewImport) {
|
|
509
|
+
return `import { loadItems } from ${JSON.stringify(actionsImport)};
|
|
510
|
+
import { ItemsView } from ${JSON.stringify(viewImport)};
|
|
511
|
+
|
|
512
|
+
export async function ItemsPanel() {
|
|
513
|
+
const data = await loadItems();
|
|
514
|
+
return <ItemsView email={data.email} workspace={data.workspace} rows={data.rows} />;
|
|
515
|
+
}
|
|
516
|
+
`;
|
|
517
|
+
}
|
|
518
|
+
function itemsViewSource(actionsImport) {
|
|
519
|
+
return `"use client";
|
|
520
|
+
|
|
521
|
+
import { Button, Input } from "@cronus-ui/ui";
|
|
522
|
+
import { createItem, deleteItem } from ${JSON.stringify(actionsImport)};
|
|
523
|
+
|
|
524
|
+
export function ItemsView({
|
|
525
|
+
email,
|
|
526
|
+
workspace,
|
|
527
|
+
rows,
|
|
528
|
+
}: {
|
|
529
|
+
email: string;
|
|
530
|
+
workspace: string;
|
|
531
|
+
rows: { id: number; title: string }[];
|
|
532
|
+
}) {
|
|
461
533
|
const count = String(rows.length);
|
|
462
534
|
return (
|
|
463
|
-
<
|
|
464
|
-
|
|
465
|
-
|
|
535
|
+
<section
|
|
536
|
+
data-slot="items-panel"
|
|
537
|
+
aria-labelledby="items-heading"
|
|
538
|
+
className="border-b border-border px-6 py-6"
|
|
539
|
+
>
|
|
540
|
+
<h2 id="items-heading" className="text-sm font-semibold text-fg">
|
|
541
|
+
Items
|
|
542
|
+
</h2>
|
|
543
|
+
<p className="mt-1 text-sm text-fg-tertiary">
|
|
544
|
+
{email} · {workspace} · {count} items
|
|
545
|
+
</p>
|
|
546
|
+
<form action={createItem} className="mt-4 flex flex-col gap-3 sm:flex-row sm:items-end">
|
|
547
|
+
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
|
548
|
+
<label htmlFor="item-title" className="text-sm font-medium text-fg">
|
|
549
|
+
Title
|
|
550
|
+
</label>
|
|
551
|
+
<Input
|
|
552
|
+
id="item-title"
|
|
553
|
+
name="title"
|
|
554
|
+
required
|
|
555
|
+
maxLength={${TITLE_MAX}}
|
|
556
|
+
autoComplete="off"
|
|
557
|
+
placeholder="New item"
|
|
558
|
+
/>
|
|
559
|
+
</div>
|
|
560
|
+
<Button type="submit">Add</Button>
|
|
561
|
+
</form>
|
|
562
|
+
{rows.length === 0 ? (
|
|
563
|
+
<p className="mt-4 text-sm text-fg-tertiary">No items yet.</p>
|
|
564
|
+
) : (
|
|
565
|
+
<ul className="mt-4">
|
|
566
|
+
{rows.map((row) => (
|
|
567
|
+
<li
|
|
568
|
+
key={row.id}
|
|
569
|
+
data-slot="item"
|
|
570
|
+
className="flex items-center justify-between gap-3 border-t border-border py-3"
|
|
571
|
+
>
|
|
572
|
+
<span className="min-w-0 truncate text-sm text-fg">{row.title}</span>
|
|
573
|
+
<form action={deleteItem}>
|
|
574
|
+
<input type="hidden" name="id" value={row.id} />
|
|
575
|
+
<Button type="submit" variant="ghost" size="sm" aria-label={"Delete " + row.title}>
|
|
576
|
+
Delete
|
|
577
|
+
</Button>
|
|
578
|
+
</form>
|
|
579
|
+
</li>
|
|
580
|
+
))}
|
|
581
|
+
</ul>
|
|
582
|
+
)}
|
|
583
|
+
</section>
|
|
466
584
|
);
|
|
467
585
|
}
|
|
468
586
|
`;
|
|
@@ -797,8 +915,8 @@ async function writeRel(targetDir, rel, content, overwrite, always, written, ski
|
|
|
797
915
|
}
|
|
798
916
|
/**
|
|
799
917
|
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
800
|
-
* Overwrites lib/auth-adapter.ts always
|
|
801
|
-
*
|
|
918
|
+
* Overwrites lib/auth-adapter.ts and lib/items.ts always. Patches the shell
|
|
919
|
+
* home page only when compose wrote it this run.
|
|
802
920
|
*/
|
|
803
921
|
export async function applyGoldPath(options) {
|
|
804
922
|
const { targetDir, config, generatedFiles, overwrite } = options;
|
|
@@ -811,6 +929,8 @@ export async function applyGoldPath(options) {
|
|
|
811
929
|
: layout.middlewareRel;
|
|
812
930
|
const authImport = `${config.aliases.lib}/auth`;
|
|
813
931
|
const authClientImport = `${config.aliases.lib}/auth-client`;
|
|
932
|
+
const itemsActionsImport = `${config.aliases.lib}/items`;
|
|
933
|
+
const itemsViewImport = "@/components/items-view";
|
|
814
934
|
const itemsImport = "@/components/items-panel";
|
|
815
935
|
const workspaceImport = "@/components/workspace-menu";
|
|
816
936
|
const inviteImport = "@/components/invite-member";
|
|
@@ -825,12 +945,26 @@ export async function applyGoldPath(options) {
|
|
|
825
945
|
{ rel: `${layout.libDir}/auth.ts`, content: authServerSource() },
|
|
826
946
|
{ rel: `${layout.libDir}/auth-client.ts`, content: authClientSource() },
|
|
827
947
|
{ rel: `${layout.libDir}/auth-adapter.ts`, content: authAdapterSource(), always: true },
|
|
948
|
+
{
|
|
949
|
+
rel: `${layout.libDir}/items.ts`,
|
|
950
|
+
content: itemsActionsSource(authImport),
|
|
951
|
+
always: true,
|
|
952
|
+
},
|
|
828
953
|
{
|
|
829
954
|
rel: `${appDir}/api/auth/[...all]/route.ts`,
|
|
830
955
|
content: authRouteSource(authImport),
|
|
831
956
|
},
|
|
832
957
|
{ rel: middlewareRel, content: middlewareSource() },
|
|
833
|
-
{
|
|
958
|
+
{
|
|
959
|
+
rel: `${layout.componentsDir}/items-panel.tsx`,
|
|
960
|
+
content: itemsPanelSource(itemsActionsImport, itemsViewImport),
|
|
961
|
+
always: true,
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
rel: `${layout.componentsDir}/items-view.tsx`,
|
|
965
|
+
content: itemsViewSource(itemsActionsImport),
|
|
966
|
+
always: true,
|
|
967
|
+
},
|
|
834
968
|
{
|
|
835
969
|
rel: `${layout.componentsDir}/workspace-menu.tsx`,
|
|
836
970
|
content: workspaceMenuSource(authClientImport),
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const CONFIG_FILE = "cronus-ui.json";
|
|
2
|
-
export declare const CLI_VERSION = "0.6.
|
|
3
|
-
export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.
|
|
2
|
+
export declare const CLI_VERSION = "0.6.3";
|
|
3
|
+
export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.3/registry";
|
|
4
4
|
/** Manifest entry `add`/`upgrade` record per installed registry item. */
|
|
5
5
|
export interface InstalledRecord {
|
|
6
6
|
/** Registry release the files came from (git tag without the leading "v"). */
|
package/dist/config.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
export const CONFIG_FILE = "cronus-ui.json";
|
|
5
|
-
export const CLI_VERSION = "0.6.
|
|
5
|
+
export const CLI_VERSION = "0.6.3";
|
|
6
6
|
export const DEFAULT_REGISTRY = `https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v${CLI_VERSION}/registry`;
|
|
7
7
|
export const DEFAULT_CONFIG = {
|
|
8
8
|
aliases: { ui: "@/components/ui", lib: "@/lib", blocks: "@/components/blocks" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cronus-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "cronus-ui — add Cronus UI components to your project, shadcn-style (copy-paste registry).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"registry:check": "bun run scripts/check-registry.ts"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@cronus-ui/ai-kit": "0.6.
|
|
57
|
+
"@cronus-ui/ai-kit": "0.6.3",
|
|
58
58
|
"commander": "^15.0.0",
|
|
59
59
|
"picocolors": "^1.1.1"
|
|
60
60
|
},
|