cronus-ui 0.6.2 → 0.6.4
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 +7 -2
- package/dist/compose/gold-path.js +365 -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.4` 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.4/registry"
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
|
@@ -37,10 +37,15 @@ export declare function goldPathLayout(config: CronusUIConfig): GoldPathLayout;
|
|
|
37
37
|
export declare function patchChromeSource(source: string, workspaceImport: string, inviteImport: string, sessionImport?: string): string | undefined;
|
|
38
38
|
/** Insert ItemsPanel into a generated home page. Returns undefined when there is no main. */
|
|
39
39
|
export declare function patchHomePageSource(source: string, itemsImport: string): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Replace the catalog TeamBlock on a generated /team page with MembersPanel.
|
|
42
|
+
* Idempotent. Returns undefined when there is no TeamBlock and no MembersPanel.
|
|
43
|
+
*/
|
|
44
|
+
export declare function patchTeamPageSource(source: string, membersImport: string): string | undefined;
|
|
40
45
|
/**
|
|
41
46
|
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
42
|
-
* Overwrites lib/auth-adapter.ts
|
|
43
|
-
* the shell home
|
|
47
|
+
* Overwrites lib/auth-adapter.ts, lib/items.ts, and lib/members.ts always.
|
|
48
|
+
* Patches the shell home and /team pages only when compose wrote them this run.
|
|
44
49
|
*/
|
|
45
50
|
export declare function applyGoldPath(options: ApplyGoldPathOptions): Promise<ApplyGoldPathResult>;
|
|
46
51
|
//# 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);
|
|
@@ -81,6 +82,13 @@ function homePageRel(appDir, generatedFiles) {
|
|
|
81
82
|
const any = generatedFiles.find((f) => /(^|\/)\(shell\)\/page\.tsx$/.test(posix(f)));
|
|
82
83
|
return any !== undefined ? posix(any) : undefined;
|
|
83
84
|
}
|
|
85
|
+
function teamPageRel(appDir, generatedFiles) {
|
|
86
|
+
const match = generatedFiles.find((f) => posix(f) === `${appDir}/(shell)/team/page.tsx`);
|
|
87
|
+
if (match !== undefined)
|
|
88
|
+
return posix(match);
|
|
89
|
+
const any = generatedFiles.find((f) => /(^|\/)\(shell\)\/team\/page\.tsx$/.test(posix(f)));
|
|
90
|
+
return any !== undefined ? posix(any) : undefined;
|
|
91
|
+
}
|
|
84
92
|
function drizzleConfigSource(dbDir) {
|
|
85
93
|
return `import { mkdirSync } from "node:fs";
|
|
86
94
|
import { dirname } from "node:path";
|
|
@@ -432,37 +440,304 @@ export const config = {
|
|
|
432
440
|
};
|
|
433
441
|
`;
|
|
434
442
|
}
|
|
435
|
-
function
|
|
436
|
-
return `
|
|
443
|
+
function itemsActionsSource(authImport) {
|
|
444
|
+
return `"use server";
|
|
445
|
+
|
|
446
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
447
|
+
import { revalidatePath } from "next/cache";
|
|
437
448
|
import { headers } from "next/headers";
|
|
438
449
|
import { db } from "@/db";
|
|
439
450
|
import { items, member, organization } from "@/db/schema";
|
|
440
451
|
import { auth } from ${JSON.stringify(authImport)};
|
|
441
452
|
|
|
442
|
-
|
|
453
|
+
const TITLE_MAX = ${TITLE_MAX};
|
|
454
|
+
|
|
455
|
+
async function activeWorkspaceId(): Promise<string | null> {
|
|
443
456
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
444
|
-
|
|
445
|
-
if (!
|
|
446
|
-
|
|
457
|
+
const userId = session?.user?.id;
|
|
458
|
+
if (!userId) return null;
|
|
459
|
+
const hinted = session.session?.activeOrganizationId ?? null;
|
|
460
|
+
if (hinted) {
|
|
461
|
+
const [membership] = await db
|
|
447
462
|
.select({ organizationId: member.organizationId })
|
|
448
463
|
.from(member)
|
|
449
|
-
.where(eq(member.userId,
|
|
464
|
+
.where(and(eq(member.userId, userId), eq(member.organizationId, hinted)))
|
|
450
465
|
.limit(1);
|
|
451
|
-
|
|
466
|
+
if (membership?.organizationId) return membership.organizationId;
|
|
452
467
|
}
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
468
|
+
const [row] = await db
|
|
469
|
+
.select({ organizationId: member.organizationId })
|
|
470
|
+
.from(member)
|
|
471
|
+
.where(eq(member.userId, userId))
|
|
472
|
+
.limit(1);
|
|
473
|
+
return row?.organizationId ?? null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export async function loadItems(): Promise<{
|
|
477
|
+
email: string;
|
|
478
|
+
workspace: string;
|
|
479
|
+
rows: { id: number; title: string }[];
|
|
480
|
+
}> {
|
|
481
|
+
const session = await auth.api.getSession({ headers: await headers() });
|
|
459
482
|
const email = session?.user?.email ?? "signed out";
|
|
460
|
-
const
|
|
483
|
+
const orgId = await activeWorkspaceId();
|
|
484
|
+
if (!orgId) return { email, workspace: "no workspace", rows: [] };
|
|
485
|
+
const [org] = await db.select().from(organization).where(eq(organization.id, orgId)).limit(1);
|
|
486
|
+
const rows = await db
|
|
487
|
+
.select({ id: items.id, title: items.title })
|
|
488
|
+
.from(items)
|
|
489
|
+
.where(eq(items.workspaceId, orgId))
|
|
490
|
+
.orderBy(desc(items.id));
|
|
491
|
+
return { email, workspace: org?.name ?? "no workspace", rows };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export async function createItem(formData: FormData) {
|
|
495
|
+
const orgId = await activeWorkspaceId();
|
|
496
|
+
if (!orgId) return;
|
|
497
|
+
const title = String(formData.get("title") ?? "")
|
|
498
|
+
.trim()
|
|
499
|
+
.slice(0, TITLE_MAX);
|
|
500
|
+
if (!title) return;
|
|
501
|
+
await db.insert(items).values({ title, workspaceId: orgId });
|
|
502
|
+
revalidatePath("/");
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export async function deleteItem(formData: FormData) {
|
|
506
|
+
const orgId = await activeWorkspaceId();
|
|
507
|
+
if (!orgId) return;
|
|
508
|
+
const id = Number(formData.get("id"));
|
|
509
|
+
if (!Number.isInteger(id) || id < 1) return;
|
|
510
|
+
await db.delete(items).where(and(eq(items.id, id), eq(items.workspaceId, orgId)));
|
|
511
|
+
revalidatePath("/");
|
|
512
|
+
}
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
function itemsPanelSource(actionsImport, viewImport) {
|
|
516
|
+
return `import { loadItems } from ${JSON.stringify(actionsImport)};
|
|
517
|
+
import { ItemsView } from ${JSON.stringify(viewImport)};
|
|
518
|
+
|
|
519
|
+
export async function ItemsPanel() {
|
|
520
|
+
const data = await loadItems();
|
|
521
|
+
return <ItemsView email={data.email} workspace={data.workspace} rows={data.rows} />;
|
|
522
|
+
}
|
|
523
|
+
`;
|
|
524
|
+
}
|
|
525
|
+
function itemsViewSource(actionsImport) {
|
|
526
|
+
return `"use client";
|
|
527
|
+
|
|
528
|
+
import { Button, Input } from "@cronus-ui/ui";
|
|
529
|
+
import { createItem, deleteItem } from ${JSON.stringify(actionsImport)};
|
|
530
|
+
|
|
531
|
+
export function ItemsView({
|
|
532
|
+
email,
|
|
533
|
+
workspace,
|
|
534
|
+
rows,
|
|
535
|
+
}: {
|
|
536
|
+
email: string;
|
|
537
|
+
workspace: string;
|
|
538
|
+
rows: { id: number; title: string }[];
|
|
539
|
+
}) {
|
|
540
|
+
const count = String(rows.length);
|
|
541
|
+
return (
|
|
542
|
+
<section
|
|
543
|
+
data-slot="items-panel"
|
|
544
|
+
aria-labelledby="items-heading"
|
|
545
|
+
className="border-b border-border px-6 py-6"
|
|
546
|
+
>
|
|
547
|
+
<h2 id="items-heading" className="text-sm font-semibold text-fg">
|
|
548
|
+
Items
|
|
549
|
+
</h2>
|
|
550
|
+
<p className="mt-1 text-sm text-fg-tertiary">
|
|
551
|
+
{email} · {workspace} · {count} items
|
|
552
|
+
</p>
|
|
553
|
+
<form action={createItem} className="mt-4 flex flex-col gap-3 sm:flex-row sm:items-end">
|
|
554
|
+
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
|
555
|
+
<label htmlFor="item-title" className="text-sm font-medium text-fg">
|
|
556
|
+
Title
|
|
557
|
+
</label>
|
|
558
|
+
<Input
|
|
559
|
+
id="item-title"
|
|
560
|
+
name="title"
|
|
561
|
+
required
|
|
562
|
+
maxLength={${TITLE_MAX}}
|
|
563
|
+
autoComplete="off"
|
|
564
|
+
placeholder="New item"
|
|
565
|
+
/>
|
|
566
|
+
</div>
|
|
567
|
+
<Button type="submit">Add</Button>
|
|
568
|
+
</form>
|
|
569
|
+
{rows.length === 0 ? (
|
|
570
|
+
<p className="mt-4 text-sm text-fg-tertiary">No items yet.</p>
|
|
571
|
+
) : (
|
|
572
|
+
<ul className="mt-4">
|
|
573
|
+
{rows.map((row) => (
|
|
574
|
+
<li
|
|
575
|
+
key={row.id}
|
|
576
|
+
data-slot="item"
|
|
577
|
+
className="flex items-center justify-between gap-3 border-t border-border py-3"
|
|
578
|
+
>
|
|
579
|
+
<span className="min-w-0 truncate text-sm text-fg">{row.title}</span>
|
|
580
|
+
<form action={deleteItem}>
|
|
581
|
+
<input type="hidden" name="id" value={row.id} />
|
|
582
|
+
<Button type="submit" variant="ghost" size="sm" aria-label={"Delete " + row.title}>
|
|
583
|
+
Delete
|
|
584
|
+
</Button>
|
|
585
|
+
</form>
|
|
586
|
+
</li>
|
|
587
|
+
))}
|
|
588
|
+
</ul>
|
|
589
|
+
)}
|
|
590
|
+
</section>
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
`;
|
|
594
|
+
}
|
|
595
|
+
function membersActionsSource(authImport) {
|
|
596
|
+
return `"use server";
|
|
597
|
+
|
|
598
|
+
import { and, asc, eq } from "drizzle-orm";
|
|
599
|
+
import { headers } from "next/headers";
|
|
600
|
+
import { db } from "@/db";
|
|
601
|
+
import { member, organization, user } from "@/db/schema";
|
|
602
|
+
import { auth } from ${JSON.stringify(authImport)};
|
|
603
|
+
|
|
604
|
+
async function activeWorkspaceId(): Promise<string | null> {
|
|
605
|
+
const session = await auth.api.getSession({ headers: await headers() });
|
|
606
|
+
const userId = session?.user?.id;
|
|
607
|
+
if (!userId) return null;
|
|
608
|
+
const hinted = session.session?.activeOrganizationId ?? null;
|
|
609
|
+
if (hinted) {
|
|
610
|
+
const [membership] = await db
|
|
611
|
+
.select({ organizationId: member.organizationId })
|
|
612
|
+
.from(member)
|
|
613
|
+
.where(and(eq(member.userId, userId), eq(member.organizationId, hinted)))
|
|
614
|
+
.limit(1);
|
|
615
|
+
if (membership?.organizationId) return membership.organizationId;
|
|
616
|
+
}
|
|
617
|
+
const [row] = await db
|
|
618
|
+
.select({ organizationId: member.organizationId })
|
|
619
|
+
.from(member)
|
|
620
|
+
.where(eq(member.userId, userId))
|
|
621
|
+
.limit(1);
|
|
622
|
+
return row?.organizationId ?? null;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export async function loadMembers(): Promise<{
|
|
626
|
+
workspace: string;
|
|
627
|
+
rows: { id: string; name: string; email: string; image: string | null; role: string }[];
|
|
628
|
+
}> {
|
|
629
|
+
const orgId = await activeWorkspaceId();
|
|
630
|
+
if (!orgId) return { workspace: "no workspace", rows: [] };
|
|
631
|
+
const [org] = await db.select().from(organization).where(eq(organization.id, orgId)).limit(1);
|
|
632
|
+
const rows = await db
|
|
633
|
+
.select({
|
|
634
|
+
id: member.id,
|
|
635
|
+
name: user.name,
|
|
636
|
+
email: user.email,
|
|
637
|
+
image: user.image,
|
|
638
|
+
role: member.role,
|
|
639
|
+
})
|
|
640
|
+
.from(member)
|
|
641
|
+
.innerJoin(user, eq(member.userId, user.id))
|
|
642
|
+
.where(eq(member.organizationId, orgId))
|
|
643
|
+
.orderBy(asc(member.createdAt));
|
|
644
|
+
return { workspace: org?.name ?? "no workspace", rows };
|
|
645
|
+
}
|
|
646
|
+
`;
|
|
647
|
+
}
|
|
648
|
+
function membersPanelSource(actionsImport, viewImport) {
|
|
649
|
+
return `import { loadMembers } from ${JSON.stringify(actionsImport)};
|
|
650
|
+
import { MembersView } from ${JSON.stringify(viewImport)};
|
|
651
|
+
|
|
652
|
+
export async function MembersPanel() {
|
|
653
|
+
const data = await loadMembers();
|
|
654
|
+
return <MembersView workspace={data.workspace} rows={data.rows} />;
|
|
655
|
+
}
|
|
656
|
+
`;
|
|
657
|
+
}
|
|
658
|
+
function membersViewSource(inviteImport) {
|
|
659
|
+
return `"use client";
|
|
660
|
+
|
|
661
|
+
import { Avatar, AvatarFallback, AvatarImage, Badge, Button } from "@cronus-ui/ui";
|
|
662
|
+
import { InviteMember } from ${JSON.stringify(inviteImport)};
|
|
663
|
+
|
|
664
|
+
function initialsOf(name: string, email: string): string {
|
|
665
|
+
const parts = name.trim().split(/\\s+/).filter(Boolean);
|
|
666
|
+
if (parts.length >= 2) {
|
|
667
|
+
return \`\${parts[0]?.[0] ?? ""}\${parts[1]?.[0] ?? ""}\`.toUpperCase();
|
|
668
|
+
}
|
|
669
|
+
if (parts[0]?.[0]) return parts[0][0].toUpperCase();
|
|
670
|
+
return email.slice(0, 2).toUpperCase();
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function roleLabel(role: string): string {
|
|
674
|
+
if (role === "owner") return "Owner";
|
|
675
|
+
if (role === "admin") return "Admin";
|
|
676
|
+
if (role === "member") return "Member";
|
|
677
|
+
return role;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function roleVariant(role: string): "primary" | "info" | "secondary" {
|
|
681
|
+
if (role === "owner") return "primary";
|
|
682
|
+
if (role === "admin") return "info";
|
|
683
|
+
return "secondary";
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export function MembersView({
|
|
687
|
+
workspace,
|
|
688
|
+
rows,
|
|
689
|
+
}: {
|
|
690
|
+
workspace: string;
|
|
691
|
+
rows: { id: string; name: string; email: string; image: string | null; role: string }[];
|
|
692
|
+
}) {
|
|
461
693
|
const count = String(rows.length);
|
|
462
694
|
return (
|
|
463
|
-
<
|
|
464
|
-
|
|
465
|
-
|
|
695
|
+
<section
|
|
696
|
+
data-slot="members-panel"
|
|
697
|
+
aria-labelledby="members-heading"
|
|
698
|
+
className="mx-auto w-full max-w-xl px-6 py-6"
|
|
699
|
+
>
|
|
700
|
+
<div className="flex items-end justify-between gap-3">
|
|
701
|
+
<div className="min-w-0">
|
|
702
|
+
<h1 id="members-heading" className="text-sm font-semibold text-fg">
|
|
703
|
+
Team
|
|
704
|
+
</h1>
|
|
705
|
+
<p className="mt-1 text-sm text-fg-tertiary">
|
|
706
|
+
{workspace} · {count} members
|
|
707
|
+
</p>
|
|
708
|
+
</div>
|
|
709
|
+
<InviteMember
|
|
710
|
+
trigger={
|
|
711
|
+
<Button type="button" size="sm">
|
|
712
|
+
Invite
|
|
713
|
+
</Button>
|
|
714
|
+
}
|
|
715
|
+
/>
|
|
716
|
+
</div>
|
|
717
|
+
{rows.length === 0 ? (
|
|
718
|
+
<p className="mt-4 text-sm text-fg-tertiary">No members yet.</p>
|
|
719
|
+
) : (
|
|
720
|
+
<ul className="mt-4">
|
|
721
|
+
{rows.map((row) => (
|
|
722
|
+
<li
|
|
723
|
+
key={row.id}
|
|
724
|
+
data-slot="member"
|
|
725
|
+
className="flex items-center gap-3 border-t border-border py-3"
|
|
726
|
+
>
|
|
727
|
+
<Avatar className="size-8">
|
|
728
|
+
{row.image ? <AvatarImage src={row.image} alt={row.name} /> : null}
|
|
729
|
+
<AvatarFallback>{initialsOf(row.name, row.email)}</AvatarFallback>
|
|
730
|
+
</Avatar>
|
|
731
|
+
<div className="flex min-w-0 flex-1 flex-col">
|
|
732
|
+
<span className="truncate text-sm text-fg">{row.name}</span>
|
|
733
|
+
<span className="truncate text-sm text-fg-tertiary">{row.email}</span>
|
|
734
|
+
</div>
|
|
735
|
+
<Badge variant={roleVariant(row.role)}>{roleLabel(row.role)}</Badge>
|
|
736
|
+
</li>
|
|
737
|
+
))}
|
|
738
|
+
</ul>
|
|
739
|
+
)}
|
|
740
|
+
</section>
|
|
466
741
|
);
|
|
467
742
|
}
|
|
468
743
|
`;
|
|
@@ -728,6 +1003,25 @@ export function patchHomePageSource(source, itemsImport) {
|
|
|
728
1003
|
}
|
|
729
1004
|
return out;
|
|
730
1005
|
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Replace the catalog TeamBlock on a generated /team page with MembersPanel.
|
|
1008
|
+
* Idempotent. Returns undefined when there is no TeamBlock and no MembersPanel.
|
|
1009
|
+
*/
|
|
1010
|
+
export function patchTeamPageSource(source, membersImport) {
|
|
1011
|
+
const hasPanel = /<MembersPanel\s*\/>/.test(source);
|
|
1012
|
+
const hasTeam = /<TeamBlock\s*\/>/.test(source);
|
|
1013
|
+
if (!hasPanel && !hasTeam)
|
|
1014
|
+
return undefined;
|
|
1015
|
+
if (hasPanel)
|
|
1016
|
+
return source;
|
|
1017
|
+
let out = source;
|
|
1018
|
+
const importLine = `import { MembersPanel } from ${JSON.stringify(membersImport)};`;
|
|
1019
|
+
out = insertImport(out, importLine);
|
|
1020
|
+
out = out.replace(/import \{ TeamBlock \} from "[^"]+";\n/, "");
|
|
1021
|
+
out = out.replace(/export default(?! async) function/, "export default async function");
|
|
1022
|
+
out = out.replace(/<TeamBlock\s*\/>/, "<MembersPanel />");
|
|
1023
|
+
return out;
|
|
1024
|
+
}
|
|
731
1025
|
function mergePackageJson(raw) {
|
|
732
1026
|
const pkg = JSON.parse(raw);
|
|
733
1027
|
const dependencies = { ...(pkg.dependencies ?? {}) };
|
|
@@ -797,8 +1091,8 @@ async function writeRel(targetDir, rel, content, overwrite, always, written, ski
|
|
|
797
1091
|
}
|
|
798
1092
|
/**
|
|
799
1093
|
* Write sqlite + Drizzle + Better-Auth files into a composed saas/admin app.
|
|
800
|
-
* Overwrites lib/auth-adapter.ts
|
|
801
|
-
* the shell home
|
|
1094
|
+
* Overwrites lib/auth-adapter.ts, lib/items.ts, and lib/members.ts always.
|
|
1095
|
+
* Patches the shell home and /team pages only when compose wrote them this run.
|
|
802
1096
|
*/
|
|
803
1097
|
export async function applyGoldPath(options) {
|
|
804
1098
|
const { targetDir, config, generatedFiles, overwrite } = options;
|
|
@@ -811,7 +1105,12 @@ export async function applyGoldPath(options) {
|
|
|
811
1105
|
: layout.middlewareRel;
|
|
812
1106
|
const authImport = `${config.aliases.lib}/auth`;
|
|
813
1107
|
const authClientImport = `${config.aliases.lib}/auth-client`;
|
|
1108
|
+
const itemsActionsImport = `${config.aliases.lib}/items`;
|
|
1109
|
+
const itemsViewImport = "@/components/items-view";
|
|
814
1110
|
const itemsImport = "@/components/items-panel";
|
|
1111
|
+
const membersActionsImport = `${config.aliases.lib}/members`;
|
|
1112
|
+
const membersViewImport = "@/components/members-view";
|
|
1113
|
+
const membersImport = "@/components/members-panel";
|
|
815
1114
|
const workspaceImport = "@/components/workspace-menu";
|
|
816
1115
|
const inviteImport = "@/components/invite-member";
|
|
817
1116
|
const sessionImport = "@/components/session-user";
|
|
@@ -825,12 +1124,41 @@ export async function applyGoldPath(options) {
|
|
|
825
1124
|
{ rel: `${layout.libDir}/auth.ts`, content: authServerSource() },
|
|
826
1125
|
{ rel: `${layout.libDir}/auth-client.ts`, content: authClientSource() },
|
|
827
1126
|
{ rel: `${layout.libDir}/auth-adapter.ts`, content: authAdapterSource(), always: true },
|
|
1127
|
+
{
|
|
1128
|
+
rel: `${layout.libDir}/items.ts`,
|
|
1129
|
+
content: itemsActionsSource(authImport),
|
|
1130
|
+
always: true,
|
|
1131
|
+
},
|
|
828
1132
|
{
|
|
829
1133
|
rel: `${appDir}/api/auth/[...all]/route.ts`,
|
|
830
1134
|
content: authRouteSource(authImport),
|
|
831
1135
|
},
|
|
832
1136
|
{ rel: middlewareRel, content: middlewareSource() },
|
|
833
|
-
{
|
|
1137
|
+
{
|
|
1138
|
+
rel: `${layout.componentsDir}/items-panel.tsx`,
|
|
1139
|
+
content: itemsPanelSource(itemsActionsImport, itemsViewImport),
|
|
1140
|
+
always: true,
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
rel: `${layout.componentsDir}/items-view.tsx`,
|
|
1144
|
+
content: itemsViewSource(itemsActionsImport),
|
|
1145
|
+
always: true,
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
rel: `${layout.libDir}/members.ts`,
|
|
1149
|
+
content: membersActionsSource(authImport),
|
|
1150
|
+
always: true,
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
rel: `${layout.componentsDir}/members-panel.tsx`,
|
|
1154
|
+
content: membersPanelSource(membersActionsImport, membersViewImport),
|
|
1155
|
+
always: true,
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
rel: `${layout.componentsDir}/members-view.tsx`,
|
|
1159
|
+
content: membersViewSource(inviteImport),
|
|
1160
|
+
always: true,
|
|
1161
|
+
},
|
|
834
1162
|
{
|
|
835
1163
|
rel: `${layout.componentsDir}/workspace-menu.tsx`,
|
|
836
1164
|
content: workspaceMenuSource(authClientImport),
|
|
@@ -870,6 +1198,22 @@ export async function applyGoldPath(options) {
|
|
|
870
1198
|
}
|
|
871
1199
|
}
|
|
872
1200
|
}
|
|
1201
|
+
const teamRel = teamPageRel(appDir, generatedFiles);
|
|
1202
|
+
if (teamRel !== undefined) {
|
|
1203
|
+
const dest = resolveSafeDest(targetDir, ".", teamRel);
|
|
1204
|
+
if (existsSync(dest)) {
|
|
1205
|
+
const current = await readFile(dest, "utf8");
|
|
1206
|
+
const patched = patchTeamPageSource(current, membersImport);
|
|
1207
|
+
if (patched !== undefined && patched !== current) {
|
|
1208
|
+
await writeFileEnsured(dest, patched);
|
|
1209
|
+
const templateName = options.templateName;
|
|
1210
|
+
if (templateName !== undefined) {
|
|
1211
|
+
const snapDest = resolveSafeDest(targetDir, baseSnapshotDir(templateName), teamRel);
|
|
1212
|
+
await writeFileEnsured(snapDest, patched);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
873
1217
|
const homeRel = homePageRel(appDir, generatedFiles);
|
|
874
1218
|
if (homeRel !== undefined) {
|
|
875
1219
|
const dest = resolveSafeDest(targetDir, ".", homeRel);
|
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.4";
|
|
3
|
+
export declare const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/pedrogbraz/cronus-ui/v0.6.4/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.4";
|
|
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.4",
|
|
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.4",
|
|
58
58
|
"commander": "^15.0.0",
|
|
59
59
|
"picocolors": "^1.1.1"
|
|
60
60
|
},
|