Lachlan McMurtrie
The app is a collaborative component builder. it begin by starting a project, entering in a description. the next page will be an ai assisted project scope, where the user will type the component type, which will be a list of core components (all that are core across ui domains). The ai will then ask for a framework of native react or react for web. the behavioral hooks, interactions and utilites that align with the component will then be showed. for web, these must be all react-aria, for native, these will be react-native. assume react-shared types for cross platform as common, as well as react-stately for states which are also cross platform. provide the user with a the data attributes as per react-aria or native equivilant documentation, ask them how they want to recieve their code files - combined as typed primitives, or separated through the use of an adapter that exports the behaviors etc to the primitive.
499a14d verified | // Shared utility functions for the application | |
| // Theme management | |
| class ThemeManager { | |
| constructor() { | |
| this.currentTheme = 'dark'; | |
| this.init(); | |
| } | |
| init() { | |
| // Check for saved theme preference or respect OS preference | |
| const savedTheme = localStorage.getItem('theme'); | |
| if (savedTheme) { | |
| this.setTheme(savedTheme); | |
| } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) { | |
| this.setTheme('dark'); | |
| } | |
| } | |
| setTheme(theme) { | |
| this.currentTheme = theme; | |
| document.documentElement.className = theme; | |
| localStorage.setItem('theme', theme); | |
| } | |
| toggleTheme() { | |
| this.setTheme(this.currentTheme === 'dark' ? 'light' : 'dark'); | |
| } | |
| } | |
| // Initialize theme manager | |
| const themeManager = new ThemeManager(); | |
| // Form validation helpers | |
| class FormValidator { | |
| static validateRequired(value) { | |
| return value && value.trim().length > 0; | |
| } | |
| static validateEmail(email) { | |
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | |
| return emailRegex.test(email); | |
| } | |
| static showError(input, message) { | |
| const errorElement = input.nextElementSibling; | |
| if (errorElement && errorElement.classList.contains('error-message')) { | |
| errorElement.textContent = message; | |
| } else { | |
| const errorDiv = document.createElement('div'); | |
| errorDiv.className = 'error-message text-red-400 text-sm mt-1'; | |
| errorDiv.textContent = message; | |
| input.parentNode.insertBefore(errorDiv, input.nextSibling); | |
| } | |
| input.classList.add('border-red-500'); | |
| } | |
| static clearError(input) { | |
| const errorElement = input.nextElementSibling; | |
| if (errorElement && errorElement.classList.contains('error-message')) { | |
| errorElement.remove(); | |
| } | |
| input.classList.remove('border-red-500'); | |
| } | |
| } | |
| // API service for AI interactions | |
| class AIService { | |
| static async generateComponentScope(description, componentType) { | |
| // Mock AI service - in real implementation, this would call your backend | |
| return new Promise((resolve) => { | |
| setTimeout(() => { | |
| const mockResponse = { | |
| frameworkOptions: ['React Web', 'React Native'], | |
| suggestedHooks: this.getSuggestedHooks(componentType), | |
| dataAttributes: this.getDataAttributes(componentType), | |
| codeStructure: ['Typed Primitives', 'Adapter Pattern'] | |
| }; | |
| resolve(mockResponse); | |
| }, 1500); | |
| }); | |
| } | |
| static getSuggestedHooks(componentType) { | |
| const hooksMap = { | |
| 'button': ['useButton', 'usePress', 'useFocusRing'], | |
| 'input': ['useTextField', 'useFocus', 'useKeyboard'], | |
| 'select': ['useSelect', 'useListBox', 'useOverlay'], | |
| 'modal': ['useDialog', 'useOverlay', 'useModal'], | |
| 'menu': ['useMenu', 'useMenuItem', 'useSubmenu'], | |
| 'tabs': ['useTab', 'useTabList', 'useTabPanel'], | |
| 'accordion': ['useAccordion', 'useAccordionItem'], | |
| 'slider': ['useSlider', 'useSliderThumb'], | |
| 'switch': ['useSwitch'], | |
| 'checkbox': ['useCheckbox', 'useCheckboxGroup'], | |
| 'radio': ['useRadio', 'useRadioGroup'] | |
| }; | |
| return hooksMap[componentType] || ['useId', 'useFocus', 'useKeyboard']; | |
| } | |
| static getDataAttributes(componentType) { | |
| const attributesMap = { | |
| 'button': ['data-focused', 'data-pressed', 'data-disabled', 'data-loading'], | |
| 'input': ['data-focused', 'data-invalid', 'data-disabled', 'data-readonly'], | |
| 'select': ['data-focused', 'data-open', 'data-disabled', 'data-invalid'], | |
| 'modal': ['data-open', 'data-placement', 'data-size'], | |
| 'menu': ['data-open', 'data-focused', 'data-disabled'], | |
| 'tabs': ['data-selected', 'data-disabled', 'data-orientation'], | |
| 'accordion': ['data-expanded', 'data-disabled'], | |
| 'slider': ['data-dragging', 'data-focused', 'data-disabled'], | |
| 'switch': ['data-selected', 'data-focused', 'data-disabled'], | |
| 'checkbox': ['data-selected', 'data-indeterminate', 'data-focused', 'data-disabled'], | |
| 'radio': ['data-selected', 'data-focused', 'data-disabled'] | |
| }; | |
| return attributesMap[componentType] || ['data-component']; | |
| } | |
| } | |
| // Local storage management | |
| class StorageManager { | |
| static getProjectData() { | |
| return { | |
| name: localStorage.getItem('projectName'), | |
| description: localStorage.getItem('projectDescription'), | |
| scope: JSON.parse(localStorage.getItem('projectScope') || '{}'), | |
| framework: localStorage.getItem('selectedFramework'), | |
| codeStructure: localStorage.getItem('selectedCodeStructure') | |
| }; | |
| } | |
| static clearProjectData() { | |
| localStorage.removeItem('projectName'); | |
| localStorage.removeItem('projectDescription'); | |
| localStorage.removeItem('projectScope'); | |
| localStorage.removeItem('selectedFramework'); | |
| localStorage.removeItem('selectedCodeStructure'); | |
| } | |
| } | |
| // Export for use in other files | |
| window.ThemeManager = ThemeManager; | |
| window.FormValidator = FormValidator; | |
| window.AIService = AIService; | |
| window.StorageManager = StorageManager; |