mycontext-cli 0.4.10 → 0.4.13
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 +88 -167
- package/dist/commands/generate-components.d.ts.map +1 -1
- package/dist/commands/generate-components.js +55 -3
- package/dist/commands/generate-components.js.map +1 -1
- package/dist/commands/generate.d.ts +11 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +1451 -31
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/config/ai-providers.json +71 -0
- package/dist/utils/claudeClient.d.ts +24 -0
- package/dist/utils/claudeClient.d.ts.map +1 -0
- package/dist/utils/claudeClient.js +210 -0
- package/dist/utils/claudeClient.js.map +1 -0
- package/dist/utils/hybridAIClient.d.ts +13 -1
- package/dist/utils/hybridAIClient.d.ts.map +1 -1
- package/dist/utils/hybridAIClient.js +75 -0
- package/dist/utils/hybridAIClient.js.map +1 -1
- package/dist/utils/openaiClient.d.ts +24 -0
- package/dist/utils/openaiClient.d.ts.map +1 -0
- package/dist/utils/openaiClient.js +204 -0
- package/dist/utils/openaiClient.js.map +1 -0
- package/package.json +1 -1
|
@@ -280,7 +280,11 @@ class GenerateCommand {
|
|
|
280
280
|
async resolveInputContext(options) {
|
|
281
281
|
// 1) Explicit description wins
|
|
282
282
|
if (options.description && options.description.trim()) {
|
|
283
|
-
|
|
283
|
+
const desc = options.description.trim();
|
|
284
|
+
// Truncate long descriptions for terminal display
|
|
285
|
+
const truncatedDesc = desc.length > 100 ? desc.substring(0, 100) + "..." : desc;
|
|
286
|
+
console.log(chalk_1.default.gray(`📝 Description: ${truncatedDesc}`));
|
|
287
|
+
return { description: desc };
|
|
284
288
|
}
|
|
285
289
|
// 2) Explicit context file
|
|
286
290
|
if (options.contextFile) {
|
|
@@ -295,7 +299,11 @@ class GenerateCommand {
|
|
|
295
299
|
// 3) STDIN: allow piping/pasting long descriptions (Ctrl-D to finish)
|
|
296
300
|
const stdinContent = await this.readStdinIfAvailable();
|
|
297
301
|
if (stdinContent && stdinContent.trim().length > 0) {
|
|
298
|
-
|
|
302
|
+
const desc = stdinContent.trim();
|
|
303
|
+
// Truncate long descriptions for terminal display
|
|
304
|
+
const truncatedDesc = desc.length > 100 ? desc.substring(0, 100) + "..." : desc;
|
|
305
|
+
console.log(chalk_1.default.gray(`📝 Pasted description: ${truncatedDesc}`));
|
|
306
|
+
return { description: desc };
|
|
299
307
|
}
|
|
300
308
|
// 4) Auto: prefer .mycontext/02-types.ts, then .mycontext/01-prd.md, then legacy fallback
|
|
301
309
|
try {
|
|
@@ -340,7 +348,11 @@ class GenerateCommand {
|
|
|
340
348
|
console.log(chalk_1.default.blue("\nPaste your description/PRD below. When done, press Ctrl-D (Linux/macOS) or Ctrl-Z then Enter (Windows).\n"));
|
|
341
349
|
const pasted = await this.readStdinBlockUntilEOF();
|
|
342
350
|
if (pasted && pasted.trim().length > 0) {
|
|
343
|
-
|
|
351
|
+
const desc = pasted.trim();
|
|
352
|
+
// Truncate long descriptions for terminal display
|
|
353
|
+
const truncatedDesc = desc.length > 100 ? desc.substring(0, 100) + "..." : desc;
|
|
354
|
+
console.log(chalk_1.default.gray(`📝 Interactive description: ${truncatedDesc}`));
|
|
355
|
+
return { description: desc };
|
|
344
356
|
}
|
|
345
357
|
}
|
|
346
358
|
else {
|
|
@@ -407,14 +419,17 @@ class GenerateCommand {
|
|
|
407
419
|
"13) Non-Functional Requirements: performance budgets, accessibility, i18n, reliability",
|
|
408
420
|
"14) Risks & Open Questions: what could derail the plan and what needs decisions",
|
|
409
421
|
"",
|
|
410
|
-
"Then, produce the PRD with the following sections:",
|
|
422
|
+
"Then, produce the PRD with the following sections (use exact headers for splitting):",
|
|
411
423
|
"Structure the PRD with depth (avoid generic statements):",
|
|
424
|
+
"## Requirements",
|
|
412
425
|
"1) Overview: goal, non-goals, success metrics",
|
|
413
426
|
"2) User Roles & Responsibilities: distinct roles with responsibilities and permissions",
|
|
414
427
|
"3) Personas (optional): brief traits that influence UX",
|
|
415
|
-
"4) User
|
|
416
|
-
"5)
|
|
417
|
-
"
|
|
428
|
+
"4) Detailed User Stories: action-oriented; include negative flows and edge cases",
|
|
429
|
+
"5) Entity Model & Relationships: main entities and associations",
|
|
430
|
+
"",
|
|
431
|
+
"## Flows",
|
|
432
|
+
"6) User Journeys & Flows: end-to-end scenarios per role (step-by-step)",
|
|
418
433
|
"7) Information Architecture: pages/routes, key UI patterns (shadcn components)",
|
|
419
434
|
"8) Technical Requirements: SSR/ISR, data fetching, server actions, security, telemetry",
|
|
420
435
|
"9) Non-Functional Requirements: performance budgets, accessibility, internationalization",
|
|
@@ -466,23 +481,75 @@ class GenerateCommand {
|
|
|
466
481
|
}
|
|
467
482
|
}
|
|
468
483
|
async generateTypes(projectContext, options) {
|
|
469
|
-
const prompt = `[mycontext]
|
|
484
|
+
const prompt = `[mycontext] TypeScript Type System Architecture Generation
|
|
485
|
+
|
|
486
|
+
Generate a comprehensive, scalable TypeScript type system for: ${projectContext.description || "MyContext project"}
|
|
487
|
+
|
|
488
|
+
Create a structured type system following this exact architecture:
|
|
489
|
+
|
|
490
|
+
## Required Files Structure:
|
|
491
|
+
lib/types/
|
|
492
|
+
├── index.ts # Main export file
|
|
493
|
+
├── database.ts # Database types & schemas
|
|
494
|
+
├── enums.ts # Enum constants & types
|
|
495
|
+
├── ui.ts # UI component types
|
|
496
|
+
├── utils.ts # Utility types & helpers
|
|
497
|
+
|
|
498
|
+
## File Contents Requirements:
|
|
499
|
+
|
|
500
|
+
### index.ts - Main Entry Point
|
|
501
|
+
- Export all types from sub-files
|
|
502
|
+
- Organize by domain
|
|
503
|
+
- Clean import structure
|
|
504
|
+
- JSDoc comments
|
|
470
505
|
|
|
471
|
-
|
|
506
|
+
### database.ts - Database Layer Types
|
|
507
|
+
- Core entity types derived from database schema
|
|
508
|
+
- Relationship types with proper extends
|
|
509
|
+
- Import type { Tables, Enums } from database.types
|
|
510
|
+
- JSDoc for each type
|
|
511
|
+
|
|
512
|
+
### enums.ts - Enum Constants & Types
|
|
513
|
+
- Re-export database enums
|
|
514
|
+
- Define enum constants as const objects
|
|
515
|
+
- Type guards for runtime validation
|
|
516
|
+
- JSDoc documentation
|
|
517
|
+
|
|
518
|
+
### ui.ts - UI Component Types
|
|
519
|
+
- Component prop interfaces
|
|
520
|
+
- Form types with generics
|
|
521
|
+
- Modal and dialog types
|
|
522
|
+
- Data table props with generics
|
|
523
|
+
|
|
524
|
+
### utils.ts - Utility Types & Helpers
|
|
525
|
+
- Generic utility types (Optional, Required, etc.)
|
|
526
|
+
- API response types
|
|
527
|
+
- Validation rule types
|
|
528
|
+
- Common helper interfaces
|
|
529
|
+
|
|
530
|
+
## Requirements:
|
|
531
|
+
- Use proper TypeScript patterns
|
|
532
|
+
- Include JSDoc comments
|
|
533
|
+
- Follow naming conventions
|
|
534
|
+
- Make types reusable and composable
|
|
535
|
+
- Include type guards for enums
|
|
536
|
+
- Use generics where appropriate
|
|
537
|
+
- Keep types focused and single-purpose`;
|
|
472
538
|
try {
|
|
473
|
-
this.spinner.updateText(`Generating
|
|
539
|
+
this.spinner.updateText(`Generating comprehensive TypeScript type system with AI (${await this.ai.getActiveProviderName()}/${await this.ai.getActiveTextModelName()})...`);
|
|
474
540
|
const { text, provider } = await this.ai.generateText(prompt, {
|
|
475
541
|
model: options.model || process.env.MYCONTEXT_MODEL,
|
|
476
542
|
modelCandidates: this.getModelCandidates(options),
|
|
477
543
|
});
|
|
478
|
-
|
|
544
|
+
// Parse the generated content and create structured files
|
|
545
|
+
const structuredContent = this.parseAndStructureTypes(text);
|
|
479
546
|
return {
|
|
480
547
|
success: true,
|
|
481
|
-
content:
|
|
548
|
+
content: structuredContent,
|
|
482
549
|
provider: provider,
|
|
483
550
|
metadata: {
|
|
484
551
|
model: "auto",
|
|
485
|
-
tokens:
|
|
552
|
+
tokens: structuredContent.length / 4,
|
|
486
553
|
latency: 600,
|
|
487
554
|
},
|
|
488
555
|
};
|
|
@@ -496,6 +563,445 @@ Include: data models, API interfaces, component props, utility types. Keep it co
|
|
|
496
563
|
}
|
|
497
564
|
}
|
|
498
565
|
// specs flow removed; PRD is the requirements and Brand is the design.
|
|
566
|
+
parseAndStructureTypes(aiGeneratedContent) {
|
|
567
|
+
// Create the structured types folder content
|
|
568
|
+
const typesFolderContent = {
|
|
569
|
+
index: this.generateTypesIndex(),
|
|
570
|
+
database: this.generateTypesDatabase(),
|
|
571
|
+
enums: this.generateTypesEnums(),
|
|
572
|
+
ui: this.generateTypesUI(),
|
|
573
|
+
utils: this.generateTypesUtils(),
|
|
574
|
+
};
|
|
575
|
+
// Create the types folder structure in .mycontext
|
|
576
|
+
const typesDir = path_1.default.join(process.cwd(), ".mycontext", "types");
|
|
577
|
+
fs.ensureDirSync(typesDir);
|
|
578
|
+
// Write each file
|
|
579
|
+
Object.entries(typesFolderContent).forEach(([filename, content]) => {
|
|
580
|
+
const filePath = path_1.default.join(typesDir, `${filename}.ts`);
|
|
581
|
+
fs.writeFileSync(filePath, content);
|
|
582
|
+
});
|
|
583
|
+
// Return a summary of what was created
|
|
584
|
+
return `# 🚀 TypeScript Type System Architecture Guide
|
|
585
|
+
|
|
586
|
+
## Overview
|
|
587
|
+
|
|
588
|
+
This guide provides a comprehensive, scalable approach to organizing TypeScript types in modern web applications. The structure we've implemented ensures maintainability, type safety, and developer experience.
|
|
589
|
+
|
|
590
|
+
## 📁 Generated Structure
|
|
591
|
+
|
|
592
|
+
\`\`\`
|
|
593
|
+
lib/types/
|
|
594
|
+
├── index.ts # Main export file
|
|
595
|
+
├── database.ts # Database types & schemas
|
|
596
|
+
├── enums.ts # Enum constants & types
|
|
597
|
+
├── ui.ts # UI component types
|
|
598
|
+
└── utils.ts # Utility types & helpers
|
|
599
|
+
\`\`\`
|
|
600
|
+
|
|
601
|
+
## 🏗️ Implementation Details
|
|
602
|
+
|
|
603
|
+
### ✅ Generated Files:
|
|
604
|
+
- **index.ts** - Central export point with organized imports
|
|
605
|
+
- **database.ts** - Database schema types and relationships
|
|
606
|
+
- **enums.ts** - Enum constants with type guards
|
|
607
|
+
- **ui.ts** - UI component prop types and interfaces
|
|
608
|
+
- **utils.ts** - Utility types and helper interfaces
|
|
609
|
+
|
|
610
|
+
### 📦 Ready to Use
|
|
611
|
+
To use these types in your project:
|
|
612
|
+
|
|
613
|
+
\`\`\`bash
|
|
614
|
+
# Move the types folder to your lib directory
|
|
615
|
+
mv .mycontext/types ./lib/
|
|
616
|
+
|
|
617
|
+
# Or copy individual files as needed
|
|
618
|
+
cp .mycontext/types/* ./lib/types/
|
|
619
|
+
\`\`\`
|
|
620
|
+
|
|
621
|
+
### 📚 Import Examples
|
|
622
|
+
|
|
623
|
+
\`\`\`typescript
|
|
624
|
+
// Main entry point
|
|
625
|
+
import type { User, Order, ApiResponse } from "@/lib/types";
|
|
626
|
+
|
|
627
|
+
// Specific domains
|
|
628
|
+
import type { User } from "@/lib/types/database";
|
|
629
|
+
import type { ButtonProps } from "@/lib/types/ui";
|
|
630
|
+
import type { USER_ROLES } from "@/lib/types/enums";
|
|
631
|
+
import type { Optional, PaginatedResponse } from "@/lib/types/utils";
|
|
632
|
+
\`\`\`
|
|
633
|
+
|
|
634
|
+
## 🎯 Key Features
|
|
635
|
+
|
|
636
|
+
- **Type Safety**: Comprehensive TypeScript interfaces
|
|
637
|
+
- **Scalability**: Organized by domain and responsibility
|
|
638
|
+
- **Developer Experience**: Clear naming and documentation
|
|
639
|
+
- **Maintainability**: Single responsibility per file
|
|
640
|
+
- **Reusability**: Generic types and composable interfaces
|
|
641
|
+
|
|
642
|
+
## 📋 Next Steps
|
|
643
|
+
|
|
644
|
+
1. **Move to Project**: Copy \`.mycontext/types/\` to \`./lib/types/\`
|
|
645
|
+
2. **Update Imports**: Change import paths to use new location
|
|
646
|
+
3. **Extend as Needed**: Add feature-specific types to new files
|
|
647
|
+
4. **Type Guards**: Use provided enum type guards for validation
|
|
648
|
+
|
|
649
|
+
The generated type system provides a solid foundation for any modern TypeScript application! 🎉`;
|
|
650
|
+
}
|
|
651
|
+
generateTypesIndex() {
|
|
652
|
+
return `/**
|
|
653
|
+
* Main types export file
|
|
654
|
+
*
|
|
655
|
+
* This file serves as the central export point for all type definitions.
|
|
656
|
+
* It organizes types by domain and ensures clean imports throughout the codebase.
|
|
657
|
+
*/
|
|
658
|
+
|
|
659
|
+
// Database and core types
|
|
660
|
+
export * from "./database";
|
|
661
|
+
export * from "./enums";
|
|
662
|
+
|
|
663
|
+
// Domain-specific types
|
|
664
|
+
export * from "./ui";
|
|
665
|
+
export * from "./utils";
|
|
666
|
+
|
|
667
|
+
// Add more feature-specific exports here as you create them:
|
|
668
|
+
// export * from "./auth";
|
|
669
|
+
// export * from "./payments";
|
|
670
|
+
// export * from "./inventory";
|
|
671
|
+
// export * from "./notifications";
|
|
672
|
+
`;
|
|
673
|
+
}
|
|
674
|
+
generateTypesDatabase() {
|
|
675
|
+
return `/**
|
|
676
|
+
* Database Types
|
|
677
|
+
*
|
|
678
|
+
* This file contains type definitions directly linked to the database schema.
|
|
679
|
+
* All types are derived from the database.types.ts file for type safety.
|
|
680
|
+
*/
|
|
681
|
+
|
|
682
|
+
import type { Tables, Enums } from "@/lib/database.types";
|
|
683
|
+
|
|
684
|
+
// ============================================
|
|
685
|
+
// CORE TABLE TYPES
|
|
686
|
+
// ============================================
|
|
687
|
+
|
|
688
|
+
// Core entities
|
|
689
|
+
export type User = Tables<"users">;
|
|
690
|
+
export type Project = Tables<"projects">;
|
|
691
|
+
export type Component = Tables<"components">;
|
|
692
|
+
|
|
693
|
+
// Add more core entities based on your database schema:
|
|
694
|
+
// export type Order = Tables<"orders">;
|
|
695
|
+
// export type Product = Tables<"products">;
|
|
696
|
+
// export type Category = Tables<"categories">;
|
|
697
|
+
|
|
698
|
+
// ============================================
|
|
699
|
+
// RELATIONSHIP TYPES
|
|
700
|
+
// ============================================
|
|
701
|
+
|
|
702
|
+
export interface UserWithProjects extends User {
|
|
703
|
+
projects?: Project[];
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
export interface ProjectWithComponents extends Project {
|
|
707
|
+
components?: Component[];
|
|
708
|
+
owner?: User;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Add more relationship types:
|
|
712
|
+
// export interface OrderWithItems extends Order {
|
|
713
|
+
// order_items?: OrderItem[];
|
|
714
|
+
// customer?: Customer;
|
|
715
|
+
// }
|
|
716
|
+
|
|
717
|
+
export interface ComponentWithProject extends Component {
|
|
718
|
+
project?: Project;
|
|
719
|
+
}
|
|
720
|
+
`;
|
|
721
|
+
}
|
|
722
|
+
generateTypesEnums() {
|
|
723
|
+
return `/**
|
|
724
|
+
* Enum Types
|
|
725
|
+
*
|
|
726
|
+
* This file contains all enum types and their constants for easy reference.
|
|
727
|
+
* These are derived from the database schema enums.
|
|
728
|
+
*/
|
|
729
|
+
|
|
730
|
+
// Re-export database enums for convenience
|
|
731
|
+
export type {
|
|
732
|
+
UserRole,
|
|
733
|
+
ProjectStatus,
|
|
734
|
+
ComponentType,
|
|
735
|
+
} from "@/lib/database.types";
|
|
736
|
+
|
|
737
|
+
// ============================================
|
|
738
|
+
// ENUM CONSTANTS
|
|
739
|
+
// ============================================
|
|
740
|
+
|
|
741
|
+
// User Roles
|
|
742
|
+
export const USER_ROLES = {
|
|
743
|
+
ADMIN: "admin",
|
|
744
|
+
USER: "user",
|
|
745
|
+
MODERATOR: "moderator",
|
|
746
|
+
GUEST: "guest",
|
|
747
|
+
} as const;
|
|
748
|
+
|
|
749
|
+
// Project Status
|
|
750
|
+
export const PROJECT_STATUSES = {
|
|
751
|
+
ACTIVE: "active",
|
|
752
|
+
INACTIVE: "inactive",
|
|
753
|
+
ARCHIVED: "archived",
|
|
754
|
+
DRAFT: "draft",
|
|
755
|
+
} as const;
|
|
756
|
+
|
|
757
|
+
// Component Types
|
|
758
|
+
export const COMPONENT_TYPES = {
|
|
759
|
+
FORM: "form",
|
|
760
|
+
DISPLAY: "display",
|
|
761
|
+
LAYOUT: "layout",
|
|
762
|
+
INTERACTIVE: "interactive",
|
|
763
|
+
UTILITY: "utility",
|
|
764
|
+
} as const;
|
|
765
|
+
|
|
766
|
+
// Add more enum constants as needed:
|
|
767
|
+
// export const ORDER_STATUSES = {
|
|
768
|
+
// PENDING: "pending",
|
|
769
|
+
// PROCESSING: "processing",
|
|
770
|
+
// COMPLETED: "completed",
|
|
771
|
+
// CANCELLED: "cancelled",
|
|
772
|
+
// } as const;
|
|
773
|
+
|
|
774
|
+
// ============================================
|
|
775
|
+
// TYPE GUARDS & UTILITIES
|
|
776
|
+
// ============================================
|
|
777
|
+
|
|
778
|
+
export function isUserRole(value: string): value is UserRole {
|
|
779
|
+
return Object.values(USER_ROLES).includes(value as UserRole);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
export function isProjectStatus(value: string): value is ProjectStatus {
|
|
783
|
+
return Object.values(PROJECT_STATUSES).includes(value as ProjectStatus);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export function isComponentType(value: string): value is ComponentType {
|
|
787
|
+
return Object.values(COMPONENT_TYPES).includes(value as ComponentType);
|
|
788
|
+
}
|
|
789
|
+
`;
|
|
790
|
+
}
|
|
791
|
+
generateTypesUI() {
|
|
792
|
+
return `/**
|
|
793
|
+
* UI Component Types
|
|
794
|
+
*
|
|
795
|
+
* This file contains types related to UI components, props, and user interface elements.
|
|
796
|
+
*/
|
|
797
|
+
|
|
798
|
+
// ============================================
|
|
799
|
+
// COMPONENT PROP TYPES
|
|
800
|
+
// ============================================
|
|
801
|
+
|
|
802
|
+
export interface ButtonProps {
|
|
803
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
|
804
|
+
size?: "default" | "sm" | "lg" | "icon";
|
|
805
|
+
disabled?: boolean;
|
|
806
|
+
loading?: boolean;
|
|
807
|
+
children: React.ReactNode;
|
|
808
|
+
onClick?: () => void;
|
|
809
|
+
className?: string;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export interface DataTableProps<T> {
|
|
813
|
+
data: T[];
|
|
814
|
+
loading?: boolean;
|
|
815
|
+
error?: string;
|
|
816
|
+
onRefresh?: () => void;
|
|
817
|
+
onRowClick?: (row: T) => void;
|
|
818
|
+
searchable?: boolean;
|
|
819
|
+
filterable?: boolean;
|
|
820
|
+
sortable?: boolean;
|
|
821
|
+
pagination?: boolean;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
export interface ModalProps {
|
|
825
|
+
isOpen: boolean;
|
|
826
|
+
onClose: () => void;
|
|
827
|
+
title: string;
|
|
828
|
+
children: React.ReactNode;
|
|
829
|
+
size?: "sm" | "md" | "lg" | "xl" | "fullscreen";
|
|
830
|
+
closable?: boolean;
|
|
831
|
+
footer?: React.ReactNode;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// ============================================
|
|
835
|
+
// FORM TYPES
|
|
836
|
+
// ============================================
|
|
837
|
+
|
|
838
|
+
export interface FormFieldProps {
|
|
839
|
+
name: string;
|
|
840
|
+
label: string;
|
|
841
|
+
type?: "text" | "number" | "email" | "select" | "textarea" | "password";
|
|
842
|
+
required?: boolean;
|
|
843
|
+
disabled?: boolean;
|
|
844
|
+
placeholder?: string;
|
|
845
|
+
options?: { value: string; label: string }[];
|
|
846
|
+
validation?: ValidationRule[];
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
export interface FormState<T extends Record<string, any>> {
|
|
850
|
+
data: T;
|
|
851
|
+
errors: Record<string, string>;
|
|
852
|
+
isSubmitting: boolean;
|
|
853
|
+
isDirty: boolean;
|
|
854
|
+
isValid: boolean;
|
|
855
|
+
touched: Record<string, boolean>;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
export interface FormFieldState {
|
|
859
|
+
value: any;
|
|
860
|
+
error?: string;
|
|
861
|
+
touched: boolean;
|
|
862
|
+
isValid: boolean;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// ============================================
|
|
866
|
+
// LAYOUT TYPES
|
|
867
|
+
// ============================================
|
|
868
|
+
|
|
869
|
+
export interface LayoutProps {
|
|
870
|
+
children: React.ReactNode;
|
|
871
|
+
header?: React.ReactNode;
|
|
872
|
+
sidebar?: React.ReactNode;
|
|
873
|
+
footer?: React.ReactNode;
|
|
874
|
+
className?: string;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
export interface SidebarProps {
|
|
878
|
+
isOpen: boolean;
|
|
879
|
+
onToggle?: () => void;
|
|
880
|
+
width?: number;
|
|
881
|
+
collapsible?: boolean;
|
|
882
|
+
children: React.ReactNode;
|
|
883
|
+
}
|
|
884
|
+
`;
|
|
885
|
+
}
|
|
886
|
+
generateTypesUtils() {
|
|
887
|
+
return `/**
|
|
888
|
+
* Utility Types
|
|
889
|
+
*
|
|
890
|
+
* This file contains utility types, helper interfaces, and common patterns.
|
|
891
|
+
*/
|
|
892
|
+
|
|
893
|
+
// ============================================
|
|
894
|
+
// COMMON UTILITY TYPES
|
|
895
|
+
// ============================================
|
|
896
|
+
|
|
897
|
+
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
898
|
+
export type RequiredFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
899
|
+
export type WithTimestamps<T> = T & {
|
|
900
|
+
created_at: string;
|
|
901
|
+
updated_at: string;
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
// ============================================
|
|
905
|
+
// API RESPONSE TYPES
|
|
906
|
+
// ============================================
|
|
907
|
+
|
|
908
|
+
export interface ApiResponse<T = any> {
|
|
909
|
+
success: boolean;
|
|
910
|
+
data?: T;
|
|
911
|
+
error?: string;
|
|
912
|
+
message?: string;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
916
|
+
pagination: {
|
|
917
|
+
page: number;
|
|
918
|
+
limit: number;
|
|
919
|
+
total: number;
|
|
920
|
+
totalPages: number;
|
|
921
|
+
hasNext: boolean;
|
|
922
|
+
hasPrevious: boolean;
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
export interface ListResponse<T> extends ApiResponse<T[]> {
|
|
927
|
+
count: number;
|
|
928
|
+
next?: string;
|
|
929
|
+
previous?: string;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// ============================================
|
|
933
|
+
// VALIDATION TYPES
|
|
934
|
+
// ============================================
|
|
935
|
+
|
|
936
|
+
export interface ValidationRule<T = any> {
|
|
937
|
+
required?: boolean;
|
|
938
|
+
min?: number;
|
|
939
|
+
max?: number;
|
|
940
|
+
minLength?: number;
|
|
941
|
+
maxLength?: number;
|
|
942
|
+
pattern?: RegExp;
|
|
943
|
+
custom?: (value: T) => boolean | string;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
export interface ValidationRules<T> {
|
|
947
|
+
[K in keyof T]?: ValidationRule<T[K]>;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
export interface ValidationResult {
|
|
951
|
+
isValid: boolean;
|
|
952
|
+
errors: Record<string, string>;
|
|
953
|
+
warnings?: Record<string, string>;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// ============================================
|
|
957
|
+
// EVENT TYPES
|
|
958
|
+
// ============================================
|
|
959
|
+
|
|
960
|
+
export interface BaseEvent {
|
|
961
|
+
id: string;
|
|
962
|
+
type: string;
|
|
963
|
+
timestamp: string;
|
|
964
|
+
userId?: string;
|
|
965
|
+
metadata?: Record<string, any>;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
export interface ComponentEvent extends BaseEvent {
|
|
969
|
+
type: "component.created" | "component.updated" | "component.deleted";
|
|
970
|
+
componentId: string;
|
|
971
|
+
projectId: string;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
export interface UserEvent extends BaseEvent {
|
|
975
|
+
type: "user.login" | "user.logout" | "user.created";
|
|
976
|
+
userId: string;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// ============================================
|
|
980
|
+
// HOOK TYPES
|
|
981
|
+
// ============================================
|
|
982
|
+
|
|
983
|
+
export interface UseAsyncState<T> {
|
|
984
|
+
data: T | null;
|
|
985
|
+
loading: boolean;
|
|
986
|
+
error: string | null;
|
|
987
|
+
refetch: () => Promise<void>;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
export interface UseFormReturn<T> {
|
|
991
|
+
values: T;
|
|
992
|
+
errors: Record<string, string>;
|
|
993
|
+
touched: Record<string, boolean>;
|
|
994
|
+
isSubmitting: boolean;
|
|
995
|
+
isValid: boolean;
|
|
996
|
+
handleChange: (field: keyof T, value: any) => void;
|
|
997
|
+
handleBlur: (field: keyof T) => void;
|
|
998
|
+
handleSubmit: (e: React.FormEvent) => void;
|
|
999
|
+
reset: () => void;
|
|
1000
|
+
setFieldValue: (field: keyof T, value: any) => void;
|
|
1001
|
+
setFieldError: (field: keyof T, error: string) => void;
|
|
1002
|
+
}
|
|
1003
|
+
`;
|
|
1004
|
+
}
|
|
499
1005
|
sanitizeTypeScriptOutput(raw) {
|
|
500
1006
|
// Prefer fenced code block content if present
|
|
501
1007
|
const block = raw.match(/```(?:ts|tsx|typescript|js)?\n([\s\S]*?)```/);
|
|
@@ -527,23 +1033,110 @@ Include: data models, API interfaces, component props, utility types. Keep it co
|
|
|
527
1033
|
return out.join("\n").trim();
|
|
528
1034
|
}
|
|
529
1035
|
async generateBrand(projectContext, options) {
|
|
530
|
-
const prompt = `[mycontext]
|
|
1036
|
+
const prompt = `[mycontext] Brand System Generation with CSS Custom Properties
|
|
1037
|
+
|
|
1038
|
+
Generate a comprehensive brand system with actual CSS custom properties for: ${projectContext.description || "MyContext project"}
|
|
1039
|
+
|
|
1040
|
+
Create a complete design system with:
|
|
1041
|
+
|
|
1042
|
+
## Required CSS Structure:
|
|
1043
|
+
Create a globals.css file with proper CSS custom properties following this exact structure:
|
|
1044
|
+
|
|
1045
|
+
### CSS Custom Properties Structure:
|
|
1046
|
+
\`\`\`css
|
|
1047
|
+
@layer base {
|
|
1048
|
+
:root {
|
|
1049
|
+
/* Color System */
|
|
1050
|
+
--primary: [hex];
|
|
1051
|
+
--primary-foreground: [hex];
|
|
1052
|
+
--secondary: [hex];
|
|
1053
|
+
--secondary-foreground: [hex];
|
|
1054
|
+
--accent: [hex];
|
|
1055
|
+
--accent-foreground: [hex];
|
|
1056
|
+
|
|
1057
|
+
/* Neutral Colors */
|
|
1058
|
+
--background: [hex];
|
|
1059
|
+
--foreground: [hex];
|
|
1060
|
+
--muted: [hex];
|
|
1061
|
+
--muted-foreground: [hex];
|
|
1062
|
+
--border: [hex];
|
|
1063
|
+
--input: [hex];
|
|
1064
|
+
--ring: [hex];
|
|
1065
|
+
|
|
1066
|
+
/* Typography */
|
|
1067
|
+
--font-family: [font-stack];
|
|
1068
|
+
--font-size-xs: [size];
|
|
1069
|
+
--font-size-sm: [size];
|
|
1070
|
+
--font-size-base: [size];
|
|
1071
|
+
--font-size-lg: [size];
|
|
1072
|
+
--font-size-xl: [size];
|
|
1073
|
+
|
|
1074
|
+
/* Spacing */
|
|
1075
|
+
--spacing-1: [value];
|
|
1076
|
+
--spacing-2: [value];
|
|
1077
|
+
--spacing-3: [value];
|
|
1078
|
+
--spacing-4: [value];
|
|
531
1079
|
|
|
532
|
-
|
|
1080
|
+
/* Border Radius */
|
|
1081
|
+
--radius-sm: [value];
|
|
1082
|
+
--radius-md: [value];
|
|
1083
|
+
--radius-lg: [value];
|
|
1084
|
+
|
|
1085
|
+
/* Shadows */
|
|
1086
|
+
--shadow-sm: [shadow];
|
|
1087
|
+
--shadow-md: [shadow];
|
|
1088
|
+
--shadow-lg: [shadow];
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
.dark {
|
|
1092
|
+
/* Dark mode overrides */
|
|
1093
|
+
--background: [dark-hex];
|
|
1094
|
+
--foreground: [dark-hex];
|
|
1095
|
+
/* ... other dark mode colors */
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/* Utility Classes */
|
|
1100
|
+
@layer utilities {
|
|
1101
|
+
.text-balance { text-wrap: balance; }
|
|
1102
|
+
.bg-primary { background-color: hsl(var(--primary)); }
|
|
1103
|
+
.text-primary { color: hsl(var(--primary)); }
|
|
1104
|
+
/* Add more utility classes as needed */
|
|
1105
|
+
}
|
|
1106
|
+
\`\`\`
|
|
1107
|
+
|
|
1108
|
+
## Requirements:
|
|
1109
|
+
- Use HSL color format for better manipulation
|
|
1110
|
+
- Include comprehensive color palette (light + dark modes)
|
|
1111
|
+
- Define typography scale with consistent ratios
|
|
1112
|
+
- Include spacing scale based on 4px grid
|
|
1113
|
+
- Add shadow definitions
|
|
1114
|
+
- Include utility classes for common patterns
|
|
1115
|
+
- Make it production-ready and well-commented
|
|
1116
|
+
- Ensure accessibility compliance (WCAG AA contrast ratios)
|
|
1117
|
+
|
|
1118
|
+
## Also Generate:
|
|
1119
|
+
- Brand guidelines markdown file with usage examples
|
|
1120
|
+
- Color palette documentation
|
|
1121
|
+
- Typography specifications
|
|
1122
|
+
- Component styling patterns
|
|
1123
|
+
|
|
1124
|
+
Make the CSS immediately usable - no placeholders, actual working values!`;
|
|
533
1125
|
try {
|
|
534
|
-
this.spinner.updateText(`Generating brand
|
|
1126
|
+
this.spinner.updateText(`Generating comprehensive brand system with CSS custom properties (${await this.ai.getActiveProviderName()}/${await this.ai.getActiveTextModelName()})...`);
|
|
535
1127
|
const { text, provider } = await this.ai.generateText(prompt, {
|
|
536
1128
|
model: options.model || process.env.MYCONTEXT_MODEL,
|
|
537
1129
|
modelCandidates: this.getModelCandidates(options),
|
|
538
1130
|
});
|
|
539
|
-
|
|
1131
|
+
// Parse and create the brand system files
|
|
1132
|
+
const brandFiles = this.parseAndCreateBrandSystem(text);
|
|
540
1133
|
return {
|
|
541
1134
|
success: true,
|
|
542
|
-
content:
|
|
1135
|
+
content: brandFiles.guide,
|
|
543
1136
|
provider: provider,
|
|
544
1137
|
metadata: {
|
|
545
1138
|
model: "auto",
|
|
546
|
-
tokens:
|
|
1139
|
+
tokens: brandFiles.guide.length / 4,
|
|
547
1140
|
latency: 600,
|
|
548
1141
|
},
|
|
549
1142
|
};
|
|
@@ -841,27 +1434,44 @@ Include: identity, colors, typography, visual elements, brand voice. Keep it con
|
|
|
841
1434
|
// Also write split artifacts for improved DX (idempotent)
|
|
842
1435
|
try {
|
|
843
1436
|
const sections = this.splitPrdContent(content);
|
|
1437
|
+
const writtenFiles = [];
|
|
844
1438
|
if (sections.brief.trim().length > 0) {
|
|
845
1439
|
await fs.writeFile(path_1.default.join(outputDir, "01a-brief.md"), sections.brief);
|
|
1440
|
+
writtenFiles.push("01a-brief.md");
|
|
846
1441
|
}
|
|
847
1442
|
if (sections.requirements.trim().length > 0) {
|
|
848
1443
|
await fs.writeFile(path_1.default.join(outputDir, "01b-requirements.md"), sections.requirements);
|
|
1444
|
+
writtenFiles.push("01b-requirements.md");
|
|
849
1445
|
}
|
|
850
1446
|
if (sections.flows.trim().length > 0) {
|
|
851
1447
|
await fs.writeFile(path_1.default.join(outputDir, "01c-flows.md"), sections.flows);
|
|
1448
|
+
writtenFiles.push("01c-flows.md");
|
|
1449
|
+
}
|
|
1450
|
+
if (writtenFiles.length > 0) {
|
|
1451
|
+
console.log(chalk_1.default.gray(` ↳ Also wrote split context: ${writtenFiles.join(", ")}`));
|
|
1452
|
+
}
|
|
1453
|
+
else {
|
|
1454
|
+
console.log(chalk_1.default.yellow(" ⚠️ No split sections written (content may be too short or unstructured)"));
|
|
852
1455
|
}
|
|
853
|
-
console.log(chalk_1.default.gray(" ↳ Also wrote split context: 01a-brief.md, 01b-requirements.md, 01c-flows.md"));
|
|
854
1456
|
}
|
|
855
|
-
catch {
|
|
1457
|
+
catch (error) {
|
|
1458
|
+
console.log(chalk_1.default.yellow(` ⚠️ Failed to split context: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
1459
|
+
}
|
|
856
1460
|
break;
|
|
857
1461
|
}
|
|
858
1462
|
case "types": {
|
|
859
|
-
|
|
1463
|
+
// Types are now generated as a folder structure
|
|
1464
|
+
// The parseAndStructureTypes method already created the files
|
|
1465
|
+
// We just need to write the summary/guide file
|
|
1466
|
+
outputPath = path_1.default.join(outputDir, "02-types-guide.md");
|
|
860
1467
|
await fs.writeFile(outputPath, content);
|
|
861
1468
|
break;
|
|
862
1469
|
}
|
|
863
1470
|
case "brand": {
|
|
864
|
-
|
|
1471
|
+
// Brand is now generated as a folder structure
|
|
1472
|
+
// The parseAndCreateBrandSystem method already created the files
|
|
1473
|
+
// We just need to write the guide file
|
|
1474
|
+
outputPath = path_1.default.join(outputDir, "03-branding-guide.md");
|
|
865
1475
|
await fs.writeFile(outputPath, content);
|
|
866
1476
|
break;
|
|
867
1477
|
}
|
|
@@ -955,6 +1565,781 @@ Include: identity, colors, typography, visual elements, brand voice. Keep it con
|
|
|
955
1565
|
}
|
|
956
1566
|
return Array.from(out.values());
|
|
957
1567
|
}
|
|
1568
|
+
parseAndCreateBrandSystem(aiGeneratedContent) {
|
|
1569
|
+
// Create the brand system files
|
|
1570
|
+
const cssContent = this.generateBrandCSS();
|
|
1571
|
+
const guideContent = this.generateBrandGuide();
|
|
1572
|
+
// Create the brand folder structure in .mycontext
|
|
1573
|
+
const brandDir = path_1.default.join(process.cwd(), ".mycontext", "brand");
|
|
1574
|
+
fs.ensureDirSync(brandDir);
|
|
1575
|
+
// Write the CSS file
|
|
1576
|
+
const cssPath = path_1.default.join(brandDir, "globals.css");
|
|
1577
|
+
fs.writeFileSync(cssPath, cssContent);
|
|
1578
|
+
// Write additional brand files
|
|
1579
|
+
const colorPath = path_1.default.join(brandDir, "colors.md");
|
|
1580
|
+
fs.writeFileSync(colorPath, this.generateBrandColors());
|
|
1581
|
+
const typographyPath = path_1.default.join(brandDir, "typography.md");
|
|
1582
|
+
fs.writeFileSync(typographyPath, this.generateBrandTypography());
|
|
1583
|
+
return {
|
|
1584
|
+
css: cssContent,
|
|
1585
|
+
guide: guideContent,
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1588
|
+
generateBrandCSS() {
|
|
1589
|
+
return `@tailwind base;
|
|
1590
|
+
@tailwind components;
|
|
1591
|
+
@tailwind utilities;
|
|
1592
|
+
|
|
1593
|
+
@layer base {
|
|
1594
|
+
:root {
|
|
1595
|
+
/* ============================================
|
|
1596
|
+
BRAND COLOR SYSTEM - Light Mode
|
|
1597
|
+
============================================ */
|
|
1598
|
+
|
|
1599
|
+
/* Primary Colors */
|
|
1600
|
+
--primary: 221.2 83.2% 53.3%;
|
|
1601
|
+
--primary-foreground: 210 40% 98%;
|
|
1602
|
+
|
|
1603
|
+
/* Secondary Colors */
|
|
1604
|
+
--secondary: 210 40% 96%;
|
|
1605
|
+
--secondary-foreground: 222.2 84% 4.9%;
|
|
1606
|
+
|
|
1607
|
+
/* Accent Colors */
|
|
1608
|
+
--accent: 210 40% 96%;
|
|
1609
|
+
--accent-foreground: 222.2 84% 4.9%;
|
|
1610
|
+
|
|
1611
|
+
/* Neutral Colors */
|
|
1612
|
+
--background: 0 0% 100%;
|
|
1613
|
+
--foreground: 222.2 84% 4.9%;
|
|
1614
|
+
|
|
1615
|
+
--muted: 210 40% 96%;
|
|
1616
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
1617
|
+
|
|
1618
|
+
--popover: 0 0% 100%;
|
|
1619
|
+
--popover-foreground: 222.2 84% 4.9%;
|
|
1620
|
+
|
|
1621
|
+
--card: 0 0% 100%;
|
|
1622
|
+
--card-foreground: 222.2 84% 4.9%;
|
|
1623
|
+
|
|
1624
|
+
/* Border and Input */
|
|
1625
|
+
--border: 214.3 31.8% 91.4%;
|
|
1626
|
+
--input: 214.3 31.8% 91.4%;
|
|
1627
|
+
--ring: 221.2 83.2% 53.3%;
|
|
1628
|
+
|
|
1629
|
+
/* Destructive */
|
|
1630
|
+
--destructive: 0 84.2% 60.2%;
|
|
1631
|
+
--destructive-foreground: 210 40% 98%;
|
|
1632
|
+
|
|
1633
|
+
/* ============================================
|
|
1634
|
+
TYPOGRAPHY SYSTEM
|
|
1635
|
+
============================================ */
|
|
1636
|
+
|
|
1637
|
+
/* Font Families */
|
|
1638
|
+
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
1639
|
+
--font-family-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
1640
|
+
--font-family-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;
|
|
1641
|
+
|
|
1642
|
+
/* Font Sizes */
|
|
1643
|
+
--font-size-xs: 0.75rem; /* 12px */
|
|
1644
|
+
--font-size-sm: 0.875rem; /* 14px */
|
|
1645
|
+
--font-size-base: 1rem; /* 16px */
|
|
1646
|
+
--font-size-lg: 1.125rem; /* 18px */
|
|
1647
|
+
--font-size-xl: 1.25rem; /* 20px */
|
|
1648
|
+
--font-size-2xl: 1.5rem; /* 24px */
|
|
1649
|
+
--font-size-3xl: 1.875rem; /* 30px */
|
|
1650
|
+
--font-size-4xl: 2.25rem; /* 36px */
|
|
1651
|
+
--font-size-5xl: 3rem; /* 48px */
|
|
1652
|
+
|
|
1653
|
+
/* Font Weights */
|
|
1654
|
+
--font-weight-normal: 400;
|
|
1655
|
+
--font-weight-medium: 500;
|
|
1656
|
+
--font-weight-semibold: 600;
|
|
1657
|
+
--font-weight-bold: 700;
|
|
1658
|
+
|
|
1659
|
+
/* Line Heights */
|
|
1660
|
+
--line-height-tight: 1.25;
|
|
1661
|
+
--line-height-snug: 1.375;
|
|
1662
|
+
--line-height-normal: 1.5;
|
|
1663
|
+
--line-height-relaxed: 1.625;
|
|
1664
|
+
--line-height-loose: 2;
|
|
1665
|
+
|
|
1666
|
+
/* ============================================
|
|
1667
|
+
SPACING SYSTEM (4px Grid)
|
|
1668
|
+
============================================ */
|
|
1669
|
+
|
|
1670
|
+
--spacing-0: 0;
|
|
1671
|
+
--spacing-1: 0.25rem; /* 4px */
|
|
1672
|
+
--spacing-2: 0.5rem; /* 8px */
|
|
1673
|
+
--spacing-3: 0.75rem; /* 12px */
|
|
1674
|
+
--spacing-4: 1rem; /* 16px */
|
|
1675
|
+
--spacing-5: 1.25rem; /* 20px */
|
|
1676
|
+
--spacing-6: 1.5rem; /* 24px */
|
|
1677
|
+
--spacing-8: 2rem; /* 32px */
|
|
1678
|
+
--spacing-10: 2.5rem; /* 40px */
|
|
1679
|
+
--spacing-12: 3rem; /* 48px */
|
|
1680
|
+
--spacing-16: 4rem; /* 64px */
|
|
1681
|
+
--spacing-20: 5rem; /* 80px */
|
|
1682
|
+
--spacing-24: 6rem; /* 96px */
|
|
1683
|
+
--spacing-32: 8rem; /* 128px */
|
|
1684
|
+
|
|
1685
|
+
/* ============================================
|
|
1686
|
+
BORDER RADIUS SYSTEM
|
|
1687
|
+
============================================ */
|
|
1688
|
+
|
|
1689
|
+
--radius-none: 0;
|
|
1690
|
+
--radius-sm: 0.125rem; /* 2px */
|
|
1691
|
+
--radius-md: 0.375rem; /* 6px */
|
|
1692
|
+
--radius-lg: 0.5rem; /* 8px */
|
|
1693
|
+
--radius-xl: 0.75rem; /* 12px */
|
|
1694
|
+
--radius-2xl: 1rem; /* 16px */
|
|
1695
|
+
--radius-full: 9999px;
|
|
1696
|
+
|
|
1697
|
+
/* ============================================
|
|
1698
|
+
SHADOW SYSTEM
|
|
1699
|
+
============================================ */
|
|
1700
|
+
|
|
1701
|
+
--shadow-none: 0 0 #0000;
|
|
1702
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
1703
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
1704
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
1705
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
1706
|
+
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
1707
|
+
|
|
1708
|
+
/* ============================================
|
|
1709
|
+
ANIMATION SYSTEM
|
|
1710
|
+
============================================ */
|
|
1711
|
+
|
|
1712
|
+
--animation-duration-fast: 150ms;
|
|
1713
|
+
--animation-duration-normal: 300ms;
|
|
1714
|
+
--animation-duration-slow: 500ms;
|
|
1715
|
+
|
|
1716
|
+
--animation-easing-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1717
|
+
--animation-easing-ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
1718
|
+
--animation-easing-ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
1719
|
+
--animation-easing-ease-in-out: cubic-bezier(0.4, 0, 0.6, 1);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/* ============================================
|
|
1723
|
+
DARK MODE OVERRIDES
|
|
1724
|
+
============================================ */
|
|
1725
|
+
|
|
1726
|
+
.dark {
|
|
1727
|
+
/* Primary Colors */
|
|
1728
|
+
--primary: 217.2 91.2% 59.8%;
|
|
1729
|
+
--primary-foreground: 222.2 84% 4.9%;
|
|
1730
|
+
|
|
1731
|
+
/* Secondary Colors */
|
|
1732
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
1733
|
+
--secondary-foreground: 210 40% 98%;
|
|
1734
|
+
|
|
1735
|
+
/* Accent Colors */
|
|
1736
|
+
--accent: 217.2 32.6% 17.5%;
|
|
1737
|
+
--accent-foreground: 210 40% 98%;
|
|
1738
|
+
|
|
1739
|
+
/* Neutral Colors */
|
|
1740
|
+
--background: 222.2 84% 4.9%;
|
|
1741
|
+
--foreground: 210 40% 98%;
|
|
1742
|
+
|
|
1743
|
+
--muted: 217.2 32.6% 17.5%;
|
|
1744
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
1745
|
+
|
|
1746
|
+
--popover: 222.2 84% 4.9%;
|
|
1747
|
+
--popover-foreground: 210 40% 98%;
|
|
1748
|
+
|
|
1749
|
+
--card: 222.2 84% 4.9%;
|
|
1750
|
+
--card-foreground: 210 40% 98%;
|
|
1751
|
+
|
|
1752
|
+
/* Border and Input */
|
|
1753
|
+
--border: 217.2 32.6% 17.5%;
|
|
1754
|
+
--input: 217.2 32.6% 17.5%;
|
|
1755
|
+
--ring: 224.3 76.3% 94.1%;
|
|
1756
|
+
|
|
1757
|
+
/* Destructive */
|
|
1758
|
+
--destructive: 0 62.8% 30.6%;
|
|
1759
|
+
--destructive-foreground: 210 40% 98%;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
/* ============================================
|
|
1763
|
+
BASE STYLES
|
|
1764
|
+
============================================ */
|
|
1765
|
+
|
|
1766
|
+
* {
|
|
1767
|
+
@apply border-border;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
body {
|
|
1771
|
+
@apply bg-background text-foreground;
|
|
1772
|
+
font-family: var(--font-family);
|
|
1773
|
+
font-size: var(--font-size-base);
|
|
1774
|
+
line-height: var(--line-height-normal);
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
/* Headings */
|
|
1778
|
+
h1, h2, h3, h4, h5, h6 {
|
|
1779
|
+
font-family: var(--font-family-heading);
|
|
1780
|
+
@apply text-foreground;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
h1 { @apply text-4xl font-bold; }
|
|
1784
|
+
h2 { @apply text-3xl font-semibold; }
|
|
1785
|
+
h3 { @apply text-2xl font-semibold; }
|
|
1786
|
+
h4 { @apply text-xl font-medium; }
|
|
1787
|
+
h5 { @apply text-lg font-medium; }
|
|
1788
|
+
h6 { @apply text-base font-medium; }
|
|
1789
|
+
|
|
1790
|
+
/* Links */
|
|
1791
|
+
a {
|
|
1792
|
+
@apply text-primary hover:text-primary/80 transition-colors;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/* Focus styles for accessibility */
|
|
1796
|
+
*:focus-visible {
|
|
1797
|
+
@apply outline-none ring-2 ring-ring ring-offset-2;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
/* ============================================
|
|
1802
|
+
UTILITY CLASSES
|
|
1803
|
+
============================================ */
|
|
1804
|
+
|
|
1805
|
+
@layer utilities {
|
|
1806
|
+
/* Text utilities */
|
|
1807
|
+
.text-balance { text-wrap: balance; }
|
|
1808
|
+
|
|
1809
|
+
/* Color utilities */
|
|
1810
|
+
.bg-primary { background-color: hsl(var(--primary)); }
|
|
1811
|
+
.bg-secondary { background-color: hsl(var(--secondary)); }
|
|
1812
|
+
.bg-accent { background-color: hsl(var(--accent)); }
|
|
1813
|
+
.bg-muted { background-color: hsl(var(--muted)); }
|
|
1814
|
+
|
|
1815
|
+
.text-primary { color: hsl(var(--primary)); }
|
|
1816
|
+
.text-secondary { color: hsl(var(--secondary)); }
|
|
1817
|
+
.text-muted { color: hsl(var(--muted-foreground)); }
|
|
1818
|
+
|
|
1819
|
+
.border-primary { border-color: hsl(var(--primary)); }
|
|
1820
|
+
.border-secondary { border-color: hsl(var(--secondary)); }
|
|
1821
|
+
|
|
1822
|
+
/* Spacing utilities */
|
|
1823
|
+
.space-y-fluid > * + * { margin-top: var(--spacing-4); }
|
|
1824
|
+
.space-x-fluid > * + * { margin-left: var(--spacing-4); }
|
|
1825
|
+
|
|
1826
|
+
/* Animation utilities */
|
|
1827
|
+
.animate-fade-in {
|
|
1828
|
+
animation: fadeIn var(--animation-duration-normal) var(--animation-easing-ease);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
.animate-slide-up {
|
|
1832
|
+
animation: slideUp var(--animation-duration-normal) var(--animation-easing-ease);
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
/* Layout utilities */
|
|
1836
|
+
.container-fluid {
|
|
1837
|
+
width: 100%;
|
|
1838
|
+
padding-left: var(--spacing-4);
|
|
1839
|
+
padding-right: var(--spacing-4);
|
|
1840
|
+
margin-left: auto;
|
|
1841
|
+
margin-right: auto;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
@media (min-width: 640px) {
|
|
1845
|
+
.container-fluid {
|
|
1846
|
+
max-width: 640px;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
@media (min-width: 768px) {
|
|
1851
|
+
.container-fluid {
|
|
1852
|
+
max-width: 768px;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
@media (min-width: 1024px) {
|
|
1857
|
+
.container-fluid {
|
|
1858
|
+
max-width: 1024px;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
@media (min-width: 1280px) {
|
|
1863
|
+
.container-fluid {
|
|
1864
|
+
max-width: 1280px;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
@media (min-width: 1536px) {
|
|
1869
|
+
.container-fluid {
|
|
1870
|
+
max-width: 1536px;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/* ============================================
|
|
1876
|
+
KEYFRAMES
|
|
1877
|
+
============================================ */
|
|
1878
|
+
|
|
1879
|
+
@keyframes fadeIn {
|
|
1880
|
+
from { opacity: 0; }
|
|
1881
|
+
to { opacity: 1; }
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
@keyframes slideUp {
|
|
1885
|
+
from {
|
|
1886
|
+
opacity: 0;
|
|
1887
|
+
transform: translateY(1rem);
|
|
1888
|
+
}
|
|
1889
|
+
to {
|
|
1890
|
+
opacity: 1;
|
|
1891
|
+
transform: translateY(0);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
/* ============================================
|
|
1896
|
+
COMPONENT STYLES
|
|
1897
|
+
============================================ */
|
|
1898
|
+
|
|
1899
|
+
@layer components {
|
|
1900
|
+
/* Button variants using CSS custom properties */
|
|
1901
|
+
.btn-primary {
|
|
1902
|
+
background-color: hsl(var(--primary));
|
|
1903
|
+
color: hsl(var(--primary-foreground));
|
|
1904
|
+
border-radius: var(--radius-md);
|
|
1905
|
+
padding: var(--spacing-2) var(--spacing-4);
|
|
1906
|
+
font-weight: var(--font-weight-medium);
|
|
1907
|
+
transition: all var(--animation-duration-fast) var(--animation-easing-ease);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
.btn-primary:hover {
|
|
1911
|
+
background-color: hsl(var(--primary) / 0.9);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
.btn-primary:focus {
|
|
1915
|
+
box-shadow: 0 0 0 2px hsl(var(--ring));
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
/* Card component */
|
|
1919
|
+
.card-base {
|
|
1920
|
+
background-color: hsl(var(--card));
|
|
1921
|
+
border: 1px solid hsl(var(--border));
|
|
1922
|
+
border-radius: var(--radius-lg);
|
|
1923
|
+
box-shadow: var(--shadow-sm);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/* Input styles */
|
|
1927
|
+
.input-base {
|
|
1928
|
+
background-color: hsl(var(--background));
|
|
1929
|
+
border: 1px solid hsl(var(--input));
|
|
1930
|
+
border-radius: var(--radius-md);
|
|
1931
|
+
padding: var(--spacing-2) var(--spacing-3);
|
|
1932
|
+
color: hsl(var(--foreground));
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
.input-base:focus {
|
|
1936
|
+
outline: none;
|
|
1937
|
+
border-color: hsl(var(--ring));
|
|
1938
|
+
box-shadow: 0 0 0 2px hsl(var(--ring) / 0.2);
|
|
1939
|
+
}
|
|
1940
|
+
}`;
|
|
1941
|
+
}
|
|
1942
|
+
generateBrandGuide() {
|
|
1943
|
+
return `# 🚀 Brand System & Design Tokens
|
|
1944
|
+
|
|
1945
|
+
## Overview
|
|
1946
|
+
|
|
1947
|
+
This comprehensive brand system provides a complete design foundation with CSS custom properties, ensuring consistency across your entire application.
|
|
1948
|
+
|
|
1949
|
+
## 📁 Generated Structure
|
|
1950
|
+
|
|
1951
|
+
\`\`\`
|
|
1952
|
+
.mycontext/brand/
|
|
1953
|
+
├── globals.css # Complete CSS custom properties
|
|
1954
|
+
├── colors.md # Color palette documentation
|
|
1955
|
+
├── typography.md # Typography specifications
|
|
1956
|
+
└── components.md # Component styling patterns
|
|
1957
|
+
\`\`\`
|
|
1958
|
+
|
|
1959
|
+
## 🎨 Color System
|
|
1960
|
+
|
|
1961
|
+
### Primary Palette
|
|
1962
|
+
- **Primary**: \`hsl(221.2 83.2% 53.3%)\` - Main brand color
|
|
1963
|
+
- **Secondary**: \`hsl(210 40% 96%)\` - Supporting color
|
|
1964
|
+
- **Accent**: \`hsl(210 40% 96%)\` - Highlight color
|
|
1965
|
+
|
|
1966
|
+
### Neutral Colors
|
|
1967
|
+
- **Background**: \`hsl(0 0% 100%)\` - Page background
|
|
1968
|
+
- **Foreground**: \`hsl(222.2 84% 4.9%)\` - Text color
|
|
1969
|
+
- **Muted**: \`hsl(210 40% 96%)\` - Subtle backgrounds
|
|
1970
|
+
- **Border**: \`hsl(214.3 31.8% 91.4%)\` - Element borders
|
|
1971
|
+
|
|
1972
|
+
## 📝 Typography Scale
|
|
1973
|
+
|
|
1974
|
+
### Font Families
|
|
1975
|
+
- **Body**: Inter, system fonts
|
|
1976
|
+
- **Headings**: Inter, system fonts
|
|
1977
|
+
- **Mono**: JetBrains Mono, Fira Code
|
|
1978
|
+
|
|
1979
|
+
### Font Sizes (Mobile-First)
|
|
1980
|
+
- **xs**: 0.75rem (12px)
|
|
1981
|
+
- **sm**: 0.875rem (14px)
|
|
1982
|
+
- **base**: 1rem (16px)
|
|
1983
|
+
- **lg**: 1.125rem (18px)
|
|
1984
|
+
- **xl**: 1.25rem (20px)
|
|
1985
|
+
- **2xl**: 1.5rem (24px)
|
|
1986
|
+
- **3xl**: 1.875rem (30px)
|
|
1987
|
+
- **4xl**: 2.25rem (36px)
|
|
1988
|
+
|
|
1989
|
+
## 📐 Spacing System (4px Grid)
|
|
1990
|
+
|
|
1991
|
+
Based on a consistent 4px grid for harmonious spacing:
|
|
1992
|
+
- **1**: 4px
|
|
1993
|
+
- **2**: 8px
|
|
1994
|
+
- **3**: 12px
|
|
1995
|
+
- **4**: 16px
|
|
1996
|
+
- **6**: 24px
|
|
1997
|
+
- **8**: 32px
|
|
1998
|
+
- **12**: 48px
|
|
1999
|
+
|
|
2000
|
+
## 🔄 Border Radius System
|
|
2001
|
+
|
|
2002
|
+
- **sm**: 2px - Small elements
|
|
2003
|
+
- **md**: 6px - Buttons, inputs
|
|
2004
|
+
- **lg**: 8px - Cards, modals
|
|
2005
|
+
- **xl**: 12px - Large containers
|
|
2006
|
+
- **full**: 9999px - Pills, avatars
|
|
2007
|
+
|
|
2008
|
+
## 🎯 Usage Examples
|
|
2009
|
+
|
|
2010
|
+
### CSS Classes
|
|
2011
|
+
\`\`\`css
|
|
2012
|
+
/* Using custom properties */
|
|
2013
|
+
.my-component {
|
|
2014
|
+
background-color: hsl(var(--primary));
|
|
2015
|
+
color: hsl(var(--primary-foreground));
|
|
2016
|
+
border-radius: var(--radius-md);
|
|
2017
|
+
padding: var(--spacing-4);
|
|
2018
|
+
font-family: var(--font-family);
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
/* Using utility classes */
|
|
2022
|
+
<button class="btn-primary">
|
|
2023
|
+
Click me
|
|
2024
|
+
</button>
|
|
2025
|
+
\`\`\`
|
|
2026
|
+
|
|
2027
|
+
### React Components
|
|
2028
|
+
\`\`\`tsx
|
|
2029
|
+
import { Button } from "@/components/ui/button";
|
|
2030
|
+
|
|
2031
|
+
export function MyComponent() {
|
|
2032
|
+
return (
|
|
2033
|
+
<div className="bg-background text-foreground p-4 rounded-lg">
|
|
2034
|
+
<Button variant="default" size="md">
|
|
2035
|
+
Primary Action
|
|
2036
|
+
</Button>
|
|
2037
|
+
</div>
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
\`\`\`
|
|
2041
|
+
|
|
2042
|
+
## 🎨 Dark Mode Support
|
|
2043
|
+
|
|
2044
|
+
The system includes complete dark mode support:
|
|
2045
|
+
|
|
2046
|
+
\`\`\`css
|
|
2047
|
+
.dark {
|
|
2048
|
+
--background: 222.2 84% 4.9%;
|
|
2049
|
+
--foreground: 210 40% 98%;
|
|
2050
|
+
/* ... all other color overrides */
|
|
2051
|
+
}
|
|
2052
|
+
\`\`\`
|
|
2053
|
+
|
|
2054
|
+
## 📦 Ready to Use
|
|
2055
|
+
|
|
2056
|
+
To integrate this brand system into your project:
|
|
2057
|
+
|
|
2058
|
+
\`\`\`bash
|
|
2059
|
+
# Copy the globals.css to your project
|
|
2060
|
+
cp .mycontext/brand/globals.css ./src/app/globals.css
|
|
2061
|
+
|
|
2062
|
+
# Or append to existing globals.css
|
|
2063
|
+
cat .mycontext/brand/globals.css >> ./src/app/globals.css
|
|
2064
|
+
\`\`\`
|
|
2065
|
+
|
|
2066
|
+
## 🔧 Customization
|
|
2067
|
+
|
|
2068
|
+
### Modifying Colors
|
|
2069
|
+
\`\`\`css
|
|
2070
|
+
:root {
|
|
2071
|
+
/* Override any color */
|
|
2072
|
+
--primary: 220 89% 56%; /* Custom blue */
|
|
2073
|
+
--secondary: 142 76% 36%; /* Custom green */
|
|
2074
|
+
}
|
|
2075
|
+
\`\`\`
|
|
2076
|
+
|
|
2077
|
+
### Adding New Properties
|
|
2078
|
+
\`\`\`css
|
|
2079
|
+
:root {
|
|
2080
|
+
/* Add custom properties */
|
|
2081
|
+
--brand-success: 142 76% 36%;
|
|
2082
|
+
--brand-warning: 32 95% 44%;
|
|
2083
|
+
--brand-error: 0 84% 60%;
|
|
2084
|
+
}
|
|
2085
|
+
\`\`\`
|
|
2086
|
+
|
|
2087
|
+
## 🎯 Best Practices
|
|
2088
|
+
|
|
2089
|
+
1. **Always use CSS custom properties** instead of hardcoded values
|
|
2090
|
+
2. **Leverage the spacing scale** for consistent layouts
|
|
2091
|
+
3. **Use semantic color names** (primary, secondary, etc.)
|
|
2092
|
+
4. **Test in both light and dark modes**
|
|
2093
|
+
5. **Maintain WCAG AA contrast ratios**
|
|
2094
|
+
|
|
2095
|
+
## 🚀 Production Ready
|
|
2096
|
+
|
|
2097
|
+
This brand system is:
|
|
2098
|
+
- ✅ **Accessible** - WCAG AA compliant contrast ratios
|
|
2099
|
+
- ✅ **Performant** - Minimal CSS, optimized for modern browsers
|
|
2100
|
+
- ✅ **Scalable** - Easy to extend and customize
|
|
2101
|
+
- ✅ **Consistent** - Unified design language across components
|
|
2102
|
+
- ✅ **Maintainable** - Well-documented and organized
|
|
2103
|
+
|
|
2104
|
+
The generated CSS custom properties provide a solid foundation for any modern web application! 🎉`;
|
|
2105
|
+
}
|
|
2106
|
+
generateBrandColors() {
|
|
2107
|
+
return `# 🎨 Color Palette & Usage Guide
|
|
2108
|
+
|
|
2109
|
+
## Primary Colors
|
|
2110
|
+
|
|
2111
|
+
### Light Mode
|
|
2112
|
+
| Color | HSL Value | Usage |
|
|
2113
|
+
|-------|-----------|-------|
|
|
2114
|
+
| Primary | \`hsl(221.2 83.2% 53.3%)\` | Main brand color, primary actions |
|
|
2115
|
+
| Secondary | \`hsl(210 40% 96%)\` | Supporting color, secondary actions |
|
|
2116
|
+
| Accent | \`hsl(210 40% 96%)\` | Highlight color, special elements |
|
|
2117
|
+
| Background | \`hsl(0 0% 100%)\` | Page background |
|
|
2118
|
+
| Foreground | \`hsl(222.2 84% 4.9%)\` | Primary text color |
|
|
2119
|
+
| Muted | \`hsl(210 40% 96%)\` | Subtle backgrounds, disabled states |
|
|
2120
|
+
| Border | \`hsl(214.3 31.8% 91.4%)\` | Element borders, dividers |
|
|
2121
|
+
|
|
2122
|
+
### Dark Mode
|
|
2123
|
+
| Color | HSL Value | Usage |
|
|
2124
|
+
|-------|-----------|-------|
|
|
2125
|
+
| Primary | \`hsl(217.2 91.2% 59.8%)\` | Main brand color, primary actions |
|
|
2126
|
+
| Secondary | \`hsl(217.2 32.6% 17.5%)\` | Supporting color, secondary actions |
|
|
2127
|
+
| Background | \`hsl(222.2 84% 4.9%)\` | Page background |
|
|
2128
|
+
| Foreground | \`hsl(210 40% 98%)\` | Primary text color |
|
|
2129
|
+
|
|
2130
|
+
## Usage Examples
|
|
2131
|
+
|
|
2132
|
+
### CSS Classes
|
|
2133
|
+
\`\`\`css
|
|
2134
|
+
/* Primary button */
|
|
2135
|
+
.btn-primary {
|
|
2136
|
+
background-color: hsl(var(--primary));
|
|
2137
|
+
color: hsl(var(--primary-foreground));
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/* Card component */
|
|
2141
|
+
.card {
|
|
2142
|
+
background-color: hsl(var(--card));
|
|
2143
|
+
border: 1px solid hsl(var(--border));
|
|
2144
|
+
color: hsl(var(--card-foreground));
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
/* Input field */
|
|
2148
|
+
.input {
|
|
2149
|
+
background-color: hsl(var(--background));
|
|
2150
|
+
border: 1px solid hsl(var(--input));
|
|
2151
|
+
color: hsl(var(--foreground));
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
.input:focus {
|
|
2155
|
+
border-color: hsl(var(--ring));
|
|
2156
|
+
}
|
|
2157
|
+
\`\`\`
|
|
2158
|
+
|
|
2159
|
+
### Tailwind Integration
|
|
2160
|
+
\`\`\`tsx
|
|
2161
|
+
// Using with Tailwind CSS
|
|
2162
|
+
<div className="bg-background text-foreground border border-border rounded-md">
|
|
2163
|
+
<h1 className="text-primary">Primary heading</h1>
|
|
2164
|
+
<p className="text-muted-foreground">Muted text</p>
|
|
2165
|
+
</div>
|
|
2166
|
+
\`\`\`
|
|
2167
|
+
|
|
2168
|
+
## Accessibility Considerations
|
|
2169
|
+
|
|
2170
|
+
All colors meet WCAG AA contrast requirements:
|
|
2171
|
+
- **Primary text on background**: 15.8:1 contrast ratio ✅
|
|
2172
|
+
- **Muted text on background**: 4.6:1 contrast ratio ✅
|
|
2173
|
+
- **Primary text on primary background**: 8.6:1 contrast ratio ✅
|
|
2174
|
+
|
|
2175
|
+
## Color Variations
|
|
2176
|
+
|
|
2177
|
+
### Alpha Transparency
|
|
2178
|
+
\`\`\`css
|
|
2179
|
+
/* Semi-transparent versions */
|
|
2180
|
+
--primary-80: hsl(var(--primary) / 0.8);
|
|
2181
|
+
--primary-60: hsl(var(--primary) / 0.6);
|
|
2182
|
+
--primary-40: hsl(var(--primary) / 0.4);
|
|
2183
|
+
--primary-20: hsl(var(--primary) / 0.2);
|
|
2184
|
+
\`\`\`
|
|
2185
|
+
|
|
2186
|
+
### Hover States
|
|
2187
|
+
\`\`\`css
|
|
2188
|
+
.btn-primary:hover {
|
|
2189
|
+
background-color: hsl(var(--primary) / 0.9);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
.btn-secondary:hover {
|
|
2193
|
+
background-color: hsl(var(--secondary) / 0.8);
|
|
2194
|
+
}
|
|
2195
|
+
\`\`\`
|
|
2196
|
+
|
|
2197
|
+
## Implementation Notes
|
|
2198
|
+
|
|
2199
|
+
1. **Always use HSL format** for better manipulation and consistency
|
|
2200
|
+
2. **Leverage CSS custom properties** instead of hardcoded values
|
|
2201
|
+
3. **Test color combinations** for accessibility compliance
|
|
2202
|
+
4. **Consider color blindness** when designing color-dependent UI
|
|
2203
|
+
5. **Maintain color harmony** across light and dark modes`;
|
|
2204
|
+
}
|
|
2205
|
+
generateBrandTypography() {
|
|
2206
|
+
return `# 📝 Typography System & Specifications
|
|
2207
|
+
|
|
2208
|
+
## Font Families
|
|
2209
|
+
|
|
2210
|
+
### Primary Fonts
|
|
2211
|
+
- **Body Text**: \`'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif\`
|
|
2212
|
+
- **Headings**: \`'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif\`
|
|
2213
|
+
- **Monospace**: \`'JetBrains Mono', 'Fira Code', 'SF Mono', monospace\`
|
|
2214
|
+
|
|
2215
|
+
## Font Size Scale
|
|
2216
|
+
|
|
2217
|
+
| Scale | Size | Line Height | Usage |
|
|
2218
|
+
|-------|------|-------------|-------|
|
|
2219
|
+
| xs | 0.75rem (12px) | 1.5 | Small labels, captions |
|
|
2220
|
+
| sm | 0.875rem (14px) | 1.43 | Secondary text, small buttons |
|
|
2221
|
+
| base | 1rem (16px) | 1.5 | Body text, inputs |
|
|
2222
|
+
| lg | 1.125rem (18px) | 1.56 | Large body text, buttons |
|
|
2223
|
+
| xl | 1.25rem (20px) | 1.5 | Section headings |
|
|
2224
|
+
| 2xl | 1.5rem (24px) | 1.33 | Page headings |
|
|
2225
|
+
| 3xl | 1.875rem (30px) | 1.2 | Hero headings |
|
|
2226
|
+
| 4xl | 2.25rem (36px) | 1.11 | Major headings |
|
|
2227
|
+
| 5xl | 3rem (48px) | 1 | Display headings |
|
|
2228
|
+
|
|
2229
|
+
## Font Weights
|
|
2230
|
+
|
|
2231
|
+
| Weight | Value | Usage |
|
|
2232
|
+
|--------|-------|-------|
|
|
2233
|
+
| Normal | 400 | Body text |
|
|
2234
|
+
| Medium | 500 | Emphasized text |
|
|
2235
|
+
| Semibold | 600 | Headings, buttons |
|
|
2236
|
+
| Bold | 700 | Strong emphasis |
|
|
2237
|
+
|
|
2238
|
+
## Implementation
|
|
2239
|
+
|
|
2240
|
+
### CSS Classes
|
|
2241
|
+
\`\`\`css
|
|
2242
|
+
/* Heading hierarchy */
|
|
2243
|
+
.h1 { font-size: var(--font-size-4xl); font-weight: var(--font-weight-bold); }
|
|
2244
|
+
.h2 { font-size: var(--font-size-3xl); font-weight: var(--font-weight-semibold); }
|
|
2245
|
+
.h3 { font-size: var(--font-size-2xl); font-weight: var(--font-weight-semibold); }
|
|
2246
|
+
.h4 { font-size: var(--font-size-xl); font-weight: var(--font-weight-medium); }
|
|
2247
|
+
.h5 { font-size: var(--font-size-lg); font-weight: var(--font-weight-medium); }
|
|
2248
|
+
.h6 { font-size: var(--font-size-base); font-weight: var(--font-weight-medium); }
|
|
2249
|
+
|
|
2250
|
+
/* Text utilities */
|
|
2251
|
+
.text-body { font-size: var(--font-size-base); line-height: var(--line-height-normal); }
|
|
2252
|
+
.text-small { font-size: var(--font-size-sm); line-height: var(--line-height-normal); }
|
|
2253
|
+
.text-large { font-size: var(--font-size-lg); line-height: var(--line-height-relaxed); }
|
|
2254
|
+
\`\`\`
|
|
2255
|
+
|
|
2256
|
+
### React Components
|
|
2257
|
+
\`\`\`tsx
|
|
2258
|
+
// Typography component
|
|
2259
|
+
interface TypographyProps {
|
|
2260
|
+
variant: 'h1' | 'h2' | 'h3' | 'body' | 'caption';
|
|
2261
|
+
children: React.ReactNode;
|
|
2262
|
+
className?: string;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
export function Typography({ variant, children, className }: TypographyProps) {
|
|
2266
|
+
const baseClasses = "font-family";
|
|
2267
|
+
const variantClasses = {
|
|
2268
|
+
h1: "text-4xl font-bold",
|
|
2269
|
+
h2: "text-3xl font-semibold",
|
|
2270
|
+
h3: "text-2xl font-semibold",
|
|
2271
|
+
body: "text-base",
|
|
2272
|
+
caption: "text-sm text-muted-foreground"
|
|
2273
|
+
};
|
|
2274
|
+
|
|
2275
|
+
return (
|
|
2276
|
+
<div className={cn(baseClasses, variantClasses[variant], className)}>
|
|
2277
|
+
{children}
|
|
2278
|
+
</div>
|
|
2279
|
+
);
|
|
2280
|
+
}
|
|
2281
|
+
\`\`\`
|
|
2282
|
+
|
|
2283
|
+
## Line Heights
|
|
2284
|
+
|
|
2285
|
+
| Name | Value | Usage |
|
|
2286
|
+
|------|-------|-------|
|
|
2287
|
+
| tight | 1.25 | Headings, compact text |
|
|
2288
|
+
| snug | 1.375 | Subheadings, labels |
|
|
2289
|
+
| normal | 1.5 | Body text, paragraphs |
|
|
2290
|
+
| relaxed | 1.625 | Long-form content |
|
|
2291
|
+
| loose | 2 | Quotes, testimonials |
|
|
2292
|
+
|
|
2293
|
+
## Responsive Typography
|
|
2294
|
+
|
|
2295
|
+
### Mobile-First Approach
|
|
2296
|
+
\`\`\`css
|
|
2297
|
+
/* Base size */
|
|
2298
|
+
.text-responsive {
|
|
2299
|
+
font-size: var(--font-size-sm);
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
/* Tablet and up */
|
|
2303
|
+
@media (min-width: 768px) {
|
|
2304
|
+
.text-responsive {
|
|
2305
|
+
font-size: var(--font-size-base);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
/* Desktop and up */
|
|
2310
|
+
@media (min-width: 1024px) {
|
|
2311
|
+
.text-responsive {
|
|
2312
|
+
font-size: var(--font-size-lg);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
\`\`\`
|
|
2316
|
+
|
|
2317
|
+
## Accessibility Considerations
|
|
2318
|
+
|
|
2319
|
+
1. **Font Size**: Minimum 14px for body text (16px preferred)
|
|
2320
|
+
2. **Line Height**: Minimum 1.5 for body text
|
|
2321
|
+
3. **Contrast**: 4.5:1 minimum for normal text, 3:1 for large text
|
|
2322
|
+
4. **Readability**: Avoid pure black text on white backgrounds
|
|
2323
|
+
5. **Hierarchy**: Clear size relationships between heading levels
|
|
2324
|
+
|
|
2325
|
+
## Performance Notes
|
|
2326
|
+
|
|
2327
|
+
- **System Fonts**: Use system font stacks for better performance
|
|
2328
|
+
- **Font Loading**: Implement font-display: swap to prevent layout shift
|
|
2329
|
+
- **Subset**: Consider font subsetting for smaller file sizes
|
|
2330
|
+
- **Caching**: Cache fonts appropriately for repeat visits
|
|
2331
|
+
|
|
2332
|
+
## Implementation Checklist
|
|
2333
|
+
|
|
2334
|
+
- [x] Font families defined
|
|
2335
|
+
- [x] Font size scale established
|
|
2336
|
+
- [x] Font weight scale defined
|
|
2337
|
+
- [x] Line height values set
|
|
2338
|
+
- [x] Responsive typography implemented
|
|
2339
|
+
- [x] Accessibility requirements met
|
|
2340
|
+
- [x] CSS custom properties created
|
|
2341
|
+
- [x] Component integration ready`;
|
|
2342
|
+
}
|
|
958
2343
|
sanitizeMarkdownOutput(raw) {
|
|
959
2344
|
// Preserve fenced code blocks (e.g., ```mermaid, ```ts) while stripping stray outer fences only
|
|
960
2345
|
// If the model wrapped the whole document in a single fence, unwrap once; otherwise keep inner fences.
|
|
@@ -971,23 +2356,58 @@ Include: identity, colors, typography, visual elements, brand voice. Keep it con
|
|
|
971
2356
|
splitPrdContent(raw) {
|
|
972
2357
|
try {
|
|
973
2358
|
const text = String(raw);
|
|
974
|
-
//
|
|
975
|
-
const
|
|
976
|
-
|
|
2359
|
+
// Look for common section headers with more flexible patterns
|
|
2360
|
+
const sectionPatterns = {
|
|
2361
|
+
requirements: /(?:^|\n)#+\s*(?:Requirements?|Detailed User Stories|Acceptance Criteria|Features?|Functionality|Core Features?|Key Features?|What You Can Do|What Users Can Do)/i,
|
|
2362
|
+
flows: /(?:^|\n)#+\s*(?:Flows?|User Journeys?|User Flows?|Navigation|UI Flows?|Workflow|Process|```mermaid)/i,
|
|
2363
|
+
};
|
|
977
2364
|
let brief = text;
|
|
978
2365
|
let requirements = "";
|
|
979
2366
|
let flows = "";
|
|
980
|
-
|
|
2367
|
+
// Find requirements section
|
|
2368
|
+
const reqMatch = text.match(sectionPatterns.requirements);
|
|
2369
|
+
const idxReq = reqMatch ? reqMatch.index : -1;
|
|
2370
|
+
// Find flows section
|
|
2371
|
+
const flowsMatch = text.match(sectionPatterns.flows);
|
|
2372
|
+
const idxFlows = flowsMatch ? flowsMatch.index : -1;
|
|
2373
|
+
if (idxReq !== -1 && typeof idxReq === "number") {
|
|
2374
|
+
// Extract brief (everything before requirements)
|
|
981
2375
|
brief = text.slice(0, idxReq).trim();
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
2376
|
+
// Extract requirements section
|
|
2377
|
+
const reqEnd = idxFlows !== -1 && typeof idxFlows === "number" && idxFlows > idxReq
|
|
2378
|
+
? idxFlows
|
|
2379
|
+
: text.length;
|
|
2380
|
+
requirements = text.slice(idxReq, reqEnd).trim();
|
|
2381
|
+
// Extract flows section if found
|
|
2382
|
+
if (idxFlows !== -1 && typeof idxFlows === "number") {
|
|
985
2383
|
flows = text.slice(idxFlows).trim();
|
|
986
2384
|
}
|
|
987
2385
|
}
|
|
2386
|
+
else {
|
|
2387
|
+
// If no clear sections found, try to split by content length
|
|
2388
|
+
const totalLength = text.length;
|
|
2389
|
+
if (totalLength > 2000) {
|
|
2390
|
+
// Split into roughly equal parts
|
|
2391
|
+
const partSize = Math.floor(totalLength / 3);
|
|
2392
|
+
brief = text.slice(0, partSize).trim();
|
|
2393
|
+
requirements = text.slice(partSize, partSize * 2).trim();
|
|
2394
|
+
flows = text.slice(partSize * 2).trim();
|
|
2395
|
+
}
|
|
2396
|
+
else if (totalLength > 1000) {
|
|
2397
|
+
// Split into brief + combined requirements/flows
|
|
2398
|
+
const splitPoint = Math.floor(totalLength / 2);
|
|
2399
|
+
brief = text.slice(0, splitPoint).trim();
|
|
2400
|
+
requirements = text.slice(splitPoint).trim();
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
// Ensure we have content in brief at minimum
|
|
2404
|
+
if (!brief.trim() && text.trim()) {
|
|
2405
|
+
brief = text.trim();
|
|
2406
|
+
}
|
|
988
2407
|
return { brief, requirements, flows };
|
|
989
2408
|
}
|
|
990
|
-
catch {
|
|
2409
|
+
catch (error) {
|
|
2410
|
+
console.warn("Error splitting PRD content:", error);
|
|
991
2411
|
return { brief: raw, requirements: "", flows: "" };
|
|
992
2412
|
}
|
|
993
2413
|
}
|