@thierrynakoa/fire-flow 12.2.1 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CREDITS.md +25 -0
- package/DOMINION-FLOW-OVERVIEW.md +182 -38
- package/README.md +399 -455
- package/TROUBLESHOOTING.md +264 -264
- package/agents/fire-debugger.md +54 -0
- package/agents/fire-executor.md +1610 -1033
- package/agents/fire-fact-checker.md +1 -1
- package/agents/fire-planner.md +85 -17
- package/agents/fire-project-researcher.md +1 -1
- package/agents/fire-researcher.md +4 -22
- package/agents/{fire-phoenix-analyst.md → fire-resurrection-analyst.md} +394 -394
- package/agents/fire-reviewer.md +552 -499
- package/agents/fire-verifier.md +114 -19
- package/bin/cli.js +18 -101
- package/commands/fire-0-orient.md +2 -2
- package/commands/fire-1a-new.md +50 -15
- package/commands/fire-1c-setup.md +33 -5
- package/commands/fire-1d-discuss.md +87 -1
- package/commands/fire-2-plan.md +556 -527
- package/commands/fire-3-execute.md +2046 -1356
- package/commands/fire-4-verify.md +975 -906
- package/commands/fire-5-handoff.md +46 -5
- package/commands/fire-6-resume.md +2 -31
- package/commands/fire-add-new-skill.md +138 -19
- package/commands/fire-autonomous.md +14 -2
- package/commands/fire-complete-milestone.md +1 -1
- package/commands/fire-cost.md +179 -183
- package/commands/fire-debug.md +1 -6
- package/commands/fire-loop-resume.md +2 -2
- package/commands/fire-loop-stop.md +1 -1
- package/commands/fire-loop.md +2 -15
- package/commands/fire-map-codebase.md +1 -1
- package/commands/fire-migrate-database.md +548 -0
- package/commands/fire-new-milestone.md +1 -1
- package/commands/fire-reflect.md +1 -2
- package/commands/fire-research.md +142 -21
- package/commands/{fire-phoenix.md → fire-resurrect.md} +859 -603
- package/commands/fire-scaffold.md +297 -0
- package/commands/fire-search.md +1 -2
- package/commands/fire-security-scan.md +483 -484
- package/commands/fire-setup.md +359 -0
- package/commands/fire-skill.md +770 -0
- package/commands/fire-skills-diff.md +506 -506
- package/commands/fire-skills-history.md +388 -388
- package/commands/fire-skills-rollback.md +7 -7
- package/commands/fire-skills-sync.md +470 -470
- package/commands/fire-test.md +5 -5
- package/commands/fire-todos.md +1 -1
- package/commands/fire-update.md +5 -5
- package/commands/fire-validate-skills.md +282 -0
- package/commands/fire-vuln-scan.md +492 -493
- package/hooks/run-hook.sh +8 -8
- package/hooks/run-session-end.sh +7 -7
- package/hooks/session-end.sh +90 -90
- package/hooks/session-start.sh +1 -1
- package/package.json +4 -24
- package/plugin.json +7 -7
- package/references/autonomy-levels.md +235 -0
- package/references/behavioral-directives.md +95 -3
- package/references/blocker-tracking.md +1 -1
- package/references/circuit-breaker.md +93 -2
- package/references/context-engineering.md +227 -9
- package/references/honesty-protocols.md +70 -1
- package/references/issue-to-pr-pipeline.md +149 -150
- package/references/metrics-and-trends.md +1 -2
- package/references/research-improvements.md +4 -108
- package/references/sdlc-mapping.md +73 -0
- package/references/state-machine.md +151 -0
- package/skills-library/AVAILABLE_TOOLS_REFERENCE.md +333 -0
- package/skills-library/SKILLS-INDEX.md +57 -558
- package/skills-library/SKILLS_LIBRARY_INDEX.md +532 -0
- package/skills-library/_general/api-patterns/api-field-name-mismatch.md +107 -0
- package/skills-library/_general/api-patterns/streaming-command-timeout.md +122 -0
- package/skills-library/_general/api-patterns/streaming-proxy-cors-bypass.md +102 -0
- package/skills-library/_general/automation/settings-gui-generator.md +172 -0
- package/skills-library/_general/database-solutions/data-type-mapping-reference.md +181 -0
- package/skills-library/_general/database-solutions/mysql-limit-offset-string-coercion.md +102 -0
- package/skills-library/_general/database-solutions/mysql-to-pg-migration.md +195 -0
- package/skills-library/_general/database-solutions/orm-schema-portability.md +193 -0
- package/skills-library/_general/database-solutions/persistent-analysis-storage.md +207 -0
- package/skills-library/_general/database-solutions/pg-to-mysql-schema-migration-methodology.md +190 -0
- package/skills-library/_general/database-solutions/sql-dialect-compatibility-matrix.md +306 -0
- package/skills-library/_general/database-solutions/sqlite-to-pg-migration.md +219 -0
- package/skills-library/_general/frontend/canvas-bubble-animation-grouping.md +270 -0
- package/skills-library/_general/frontend/color-token-migration.md +112 -0
- package/skills-library/_general/frontend/framer-motion-layoutid-grouping.md +150 -0
- package/skills-library/_general/frontend/pyqt6-settings-dialog.md +191 -0
- package/skills-library/_general/frontend/react-flow-animated-layout-switching.md +101 -0
- package/skills-library/_general/frontend/react-hooks-order-debugging.md +141 -0
- package/skills-library/_general/frontend/redux-localstorage-auth-desync.md +126 -0
- package/skills-library/_general/frontend/safari-csp-theme-color-debugging.md +124 -0
- package/skills-library/_general/frontend/safari-sw-cache-poisoning.md +138 -0
- package/skills-library/_general/frontend/svg-sparkline-no-charting-library.md +131 -0
- package/skills-library/_general/growth-marketing/oss-daily-growth-intelligence.md +224 -0
- package/skills-library/_general/integrations/claude-code-local-mcp-integration.md +250 -0
- package/skills-library/_general/integrations/mcp-composite-tool-orchestration.md +200 -0
- package/skills-library/_general/methodology/AGENT_SDK_STANDALONE_TOOLING.md +181 -0
- package/skills-library/_general/methodology/AGENT_TEAMS_GUIDE.md +169 -0
- package/skills-library/_general/methodology/ALAS_STATEFUL_EXECUTION.md +207 -0
- package/skills-library/_general/methodology/AUTO_REVIEWER_SUBAGENT.md +211 -0
- package/skills-library/_general/methodology/CONSISTENCY_CHECK_AMBIGUITY_GATE.md +96 -0
- package/skills-library/_general/methodology/DEAD_ENDS_SHELF.md +4 -4
- package/skills-library/_general/methodology/DISTILL_NOT_DUMP.md +108 -0
- package/skills-library/_general/methodology/EXECUTION_PROGRESS_MONITOR.md +157 -0
- package/skills-library/_general/methodology/HIERARCHICAL_REVIEW_MARS.md +122 -0
- package/skills-library/_general/methodology/MCP_INTER_AGENT_BRIDGE.md +207 -0
- package/skills-library/_general/methodology/MERMAID_WIZARD_DIAGRAMS.md +77 -0
- package/skills-library/_general/methodology/MISSING_DIMENSION_DETECTOR.md +89 -0
- package/skills-library/_general/methodology/MULTI_AGENT_COORDINATION.md +397 -0
- package/skills-library/_general/methodology/OBSERVATION_MASKING.md +100 -0
- package/skills-library/_general/methodology/PHOENIX_REBUILD_METHODOLOGY.md +82 -11
- package/skills-library/_general/methodology/REVIEW_BACKTRACK_PANEL.md +140 -0
- package/skills-library/_general/methodology/REVIEW_FIX_LOOP.md +117 -0
- package/skills-library/_general/methodology/VOTING_VERDICT_ARBITRATION.md +155 -0
- package/skills-library/_general/methodology/ZERO_FRICTION_CLI_SETUP.md +2 -2
- package/skills-library/_general/methodology/dead-code-activation.md +123 -0
- package/skills-library/_general/methodology/debug-swarm-researcher-escape-hatch.md +240 -240
- package/skills-library/_general/methodology/shell-autonomous-loop-fixplan.md +1 -1
- package/skills-library/_general/patterns-standards/GOF_DESIGN_PATTERNS_FOR_AI_AGENTS.md +5 -5
- package/skills-library/_general/patterns-standards/cascading-failure-diagnosis.md +119 -0
- package/skills-library/_general/patterns-standards/domain-specific-layout-algorithms.md +209 -0
- package/skills-library/_general/patterns-standards/python-desktop-app-architecture.md +399 -0
- package/skills-library/_general/patterns-standards/realtime-monitoring-dashboard.md +457 -0
- package/skills-library/_general/patterns-standards/togglable-processing-pipeline.md +169 -0
- package/skills-library/_general/performance/liveclock-extraction.md +112 -0
- package/skills-library/_general/performance/ref-based-canvas-animation.md +117 -0
- package/skills-library/_general/performance/use-visible-interval.md +131 -0
- package/skills-library/_general/testing/playwright-firefox-withcredentials-auth-issue.md +104 -0
- package/skills-library/_quarantine/README.md +30 -0
- package/skills-library/api-patterns/BROADCAST_SCHEDULER_SHARED_EXECUTE_FUNCTION.md +150 -0
- package/skills-library/api-patterns/ERROR_RESPONSE_STANDARDS.md +145 -0
- package/skills-library/api-patterns/EXPRESS_ROUTE_ORDERING_MIDDLEWARE_INTERCEPTION.md +326 -0
- package/skills-library/api-patterns/PAGINATION_PATTERNS.md +137 -0
- package/skills-library/api-patterns/PODCAST_PROGRESS_TRACKING_THREE_ROOT_CAUSES.md +277 -0
- package/skills-library/api-patterns/RATE_LIMITING_TOGGLE.md +155 -0
- package/skills-library/api-patterns/graphql-content-queries.md +708 -0
- package/skills-library/appointment-scheduler-design.md +423 -0
- package/skills-library/automation/AUTO_POPULATE_COMPLETE_GUIDE.md +631 -0
- package/skills-library/automation/CC_WORKFLOW_STUDIO.md +83 -0
- package/skills-library/automation/CLAUDE_CODE_SWARM_MODE.md +95 -0
- package/skills-library/automation/DAEMON_TRIGGER_FILE_IPC.md +195 -0
- package/skills-library/automation/scheduled-content-publishing.md +608 -0
- package/skills-library/awesome-workflows/Blogging-Platform-Instructions/view_commands.md +25 -0
- package/skills-library/awesome-workflows/CREDENTIAL-SECURITY-WORKFLOW.md +109 -0
- package/skills-library/awesome-workflows/DEBUGGING-WORKFLOW.md +124 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/README.md +31 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-principles-example.md +129 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-agent.md +107 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-claude-md-snippet.md +24 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-slash-command.md +38 -0
- package/skills-library/awesome-workflows/PARALLEL-RESEARCH-WORKFLOW.md +89 -0
- package/skills-library/awesome-workflows/PHASE-EXECUTION-WORKFLOW.md +97 -0
- package/skills-library/awesome-workflows/SESSION-HANDOFF-WORKFLOW.md +116 -0
- package/skills-library/cms-patterns/content-branch-preview.md +515 -0
- package/skills-library/cms-patterns/inline-visual-editing.md +666 -0
- package/skills-library/cms-patterns/mdx-component-content.md +649 -0
- package/skills-library/cms-patterns/media-manager-abstraction.md +827 -0
- package/skills-library/cms-patterns/schema-driven-form-generator.md +838 -0
- package/skills-library/complexity-metrics/complexity-divider.md +707 -0
- package/skills-library/complexity-metrics/work-with-complexity.md +193 -0
- package/skills-library/creative-multimedia/animation-stack-guide.md +577 -0
- package/skills-library/creative-multimedia/audio-enhancement-pipeline.md +625 -0
- package/skills-library/creative-multimedia/content-repurposing-pipeline.md +1146 -0
- package/skills-library/creative-multimedia/data-visualization-generator.md +862 -0
- package/skills-library/creative-multimedia/doc-to-podcast-pipeline.md +2184 -0
- package/skills-library/creative-multimedia/ffmpeg-command-generator.md +405 -0
- package/skills-library/creative-multimedia/image-optimization-pipeline.md +605 -0
- package/skills-library/creative-multimedia/multi-format-content-generator.md +1759 -0
- package/skills-library/creative-multimedia/og-image-generator.md +635 -0
- package/skills-library/creative-multimedia/podcast-audio-composition.md +1355 -0
- package/skills-library/creative-multimedia/podcast-quality-evaluation.md +1452 -0
- package/skills-library/creative-multimedia/podcast-script-generation.md +1841 -0
- package/skills-library/creative-multimedia/svg-generation.md +750 -0
- package/skills-library/creative-multimedia/text-to-speech-provider-selector.md +1414 -0
- package/skills-library/creative-multimedia/transcription-pipeline-selector.md +677 -0
- package/skills-library/creative-multimedia/video-streaming-setup.md +559 -0
- package/skills-library/database-solutions/AI_RESPONSE_DATABASE_CACHING.md +520 -0
- package/skills-library/database-solutions/CONDITIONAL_SQL_MIGRATION_PATTERN.md +119 -0
- package/skills-library/database-solutions/DATABASE_COLUMN_NAME_MISMATCH.md +393 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA.md +394 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA_VERIFICATION_GUIDE.md +348 -0
- package/skills-library/database-solutions/DATABASE_STRATEGY.md +71 -0
- package/skills-library/database-solutions/ES_MODULE_SEED_SCRIPT_PATTERN.md +52 -0
- package/skills-library/database-solutions/MIGRATION_GUIDE.md +3 -0
- package/skills-library/database-solutions/PLPGSQL_VARIABLE_CONFLICT_FIX.md +208 -0
- package/skills-library/database-solutions/POSTGRESQL_JSONB_DOUBLE_STRINGIFY_FIX.md +245 -0
- package/skills-library/database-solutions/POSTGRESQL_LICENSE_TABLE_DESIGN.md +393 -0
- package/skills-library/database-solutions/POSTGRESQL_UUID_DOCUMENT_RAG_DUAL_SCOPE.md +732 -0
- package/skills-library/database-solutions/POSTGRES_SQL_TEMPLATE_BINDING_ERROR.md +240 -0
- package/skills-library/database-solutions/PRISMA_DB_PUSH_DATA_LOSS_PREVENTION.md +141 -0
- package/skills-library/database-solutions/PRODUCTION_QUERY_OPTIMIZATION_RESTART_FIX.md +389 -0
- package/skills-library/database-solutions/RLS_SECURITY_GUIDE.md +107 -0
- package/skills-library/database-solutions/SCHEMA_ENHANCEMENTS_GUIDE.md +373 -0
- package/skills-library/database-solutions/SCHEMA_MIGRATION_GUIDE.md +368 -0
- package/skills-library/database-solutions/SCHEMA_VERIFICATION_QUICK_REFERENCE.md +104 -0
- package/skills-library/database-solutions/ai-erd-generator.md +1213 -0
- package/skills-library/database-solutions/content-publishing-states.md +631 -0
- package/skills-library/database-solutions/database-schema-designer.md +522 -0
- package/skills-library/database-solutions/er-diagram-components.md +569 -0
- package/skills-library/database-solutions/er-to-ddl-mapping.md +1405 -0
- package/skills-library/database-solutions/erd-creator-textbook-research.md +433 -0
- package/skills-library/database-solutions/erd-react-flow-architecture.md +1965 -0
- package/skills-library/database-solutions/mariadb-aggregate-function-replacement.md +145 -0
- package/skills-library/database-solutions/normalization-validator.md +778 -0
- package/skills-library/database-solutions/postgres-full-text-search-content.md +494 -0
- package/skills-library/database-solutions/postgresql-to-mysql-runtime-translation.md +286 -0
- package/skills-library/database-solutions/regex-alternation-ordering-sql-types.md +92 -0
- package/skills-library/database-solutions/reserved-word-context-aware-quoting.md +142 -0
- package/skills-library/database-solutions/sql-ddl-generator.md +756 -0
- package/skills-library/database-solutions/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/deployment-security/CPANEL_NODE_DEPLOYMENT.md +166 -0
- package/skills-library/deployment-security/DEPLOYMENT.md +275 -0
- package/skills-library/deployment-security/DEPLOYMENT_CHECKLIST.md +363 -0
- package/skills-library/deployment-security/DEPLOYMENT_PLAN.md +669 -0
- package/skills-library/deployment-security/KNEX_DATABASE_ABSTRACTION.md +444 -0
- package/skills-library/deployment-security/LICENSE_KEY_SYSTEM.md +206 -0
- package/skills-library/deployment-security/NODE18_DEPENDENCY_COMPATIBILITY.md +284 -0
- package/skills-library/deployment-security/PHP_INSTALLER_WIZARD_GUIDE.md +315 -0
- package/skills-library/deployment-security/PM2_ENVIRONMENT_VARIABLE_CACHING.md +256 -0
- package/skills-library/deployment-security/PM2_MEMORY_EXHAUSTION_FIX.md +370 -0
- package/skills-library/deployment-security/PRODUCTION_DEPLOYMENT_GUIDE.md +592 -0
- package/skills-library/deployment-security/PRODUCTION_HARDENING_DOCUMENTATION.md +307 -0
- package/skills-library/deployment-security/PRODUCTION_RECOVERY_CHERRY_PICK_PATTERN.md +202 -0
- package/skills-library/deployment-security/PYINSTALLER_CUDA_WHISPER_BUNDLING.md +236 -0
- package/skills-library/deployment-security/SECURITY.md +41 -0
- package/skills-library/deployment-security/SMTP_SSL_HOSTNAME_MISMATCH_SHARED_HOSTING.md +220 -0
- package/skills-library/deployment-security/SPA_SEO_OPTIMIZATION_CPANEL.md +200 -0
- package/skills-library/deployment-security/SUPABASE_EDGE_FUNCTIONS.md +338 -0
- package/skills-library/deployment-security/VERCEL_GITHUB_DEPLOYMENT_GUIDE.md +858 -0
- package/skills-library/deployment-security/VPS_DEPLOYMENT_READINESS.md +356 -0
- package/skills-library/deployment-security/deployment-changes-not-applying.md +241 -0
- package/skills-library/deployment-security/env-file-management-production-local.md +203 -0
- package/skills-library/deployment-security/express-secure-file-downloads.md +413 -0
- package/skills-library/deployment-security/react-production-deployment-desktop-guide.md +2011 -0
- package/skills-library/deployment-security/self-hosted-supabase-coolify-guide.md +1684 -0
- package/skills-library/deployment-security/unique-features-ai-strategy-plaid-security.md +1613 -0
- package/skills-library/deployment-security/vps-deployment.md +135 -0
- package/skills-library/document-processing/WORD_EXPORT_MARKDOWN_FORMATTING.md +482 -0
- package/skills-library/document-processing/document-ai-landingai-integration.md +677 -0
- package/skills-library/document-processing/express-secure-file-downloads-mern.md +413 -0
- package/skills-library/document-processing/express-secure-file-downloads.md +413 -0
- package/skills-library/document-processing/md-to-word-converter.md +318 -0
- package/skills-library/document-processing/pdf-forms-integration/README.md +101 -0
- package/skills-library/document-processing/pdf-forms-integration/SKILL.md +662 -0
- package/skills-library/ecommerce/ADMIN_PRODUCTS_GUIDE.md +428 -0
- package/skills-library/ecommerce/ECOMMERCE_API_REFERENCE.md +776 -0
- package/skills-library/ecommerce/ECOMMERCE_COMPLETION_SUMMARY.md +673 -0
- package/skills-library/ecommerce/ECOMMERCE_IMPLEMENTATION_GUIDE.md +729 -0
- package/skills-library/ecommerce/ECOMMERCE_QUICK_REFERENCE.md +521 -0
- package/skills-library/ecommerce/ECOMMERCE_TESTING_CHECKLIST.md +565 -0
- package/skills-library/ecommerce/ECOMMERCE_WORKFLOW_GUIDE.md +1059 -0
- package/skills-library/ecommerce/PRODUCT_CREATION_EXPANDED.md +522 -0
- package/skills-library/ecommerce/agentic-commerce-protocol.md +203 -0
- package/skills-library/ecommerce/cart-abandonment-recovery.md +236 -0
- package/skills-library/ecommerce/cart-architecture-patterns.md +300 -0
- package/skills-library/ecommerce/cart-item-count-indicator.md +264 -0
- package/skills-library/ecommerce/checkout-ux-conversion.md +227 -0
- package/skills-library/ecommerce/composable-commerce-selection.md +166 -0
- package/skills-library/ecommerce/ecommerce-analytics-patterns.md +167 -0
- package/skills-library/ecommerce/fraud-detection-patterns.md +179 -0
- package/skills-library/ecommerce/inventory-stock-management.md +270 -0
- package/skills-library/ecommerce/order-saga-state-machine.md +336 -0
- package/skills-library/ecommerce/payment-provider-abstraction.md +245 -0
- package/skills-library/ecommerce/pci-compliance-checklist.md +192 -0
- package/skills-library/ecommerce/refund-chargeback-handling.md +177 -0
- package/skills-library/ecommerce/shipping-carrier-integration.md +218 -0
- package/skills-library/ecommerce/webhook-idempotency-patterns.md +253 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/ci.yml +558 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/prompt-gallery.yml +448 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/release.yml +42 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/test-reusable-ci.yml +25 -0
- package/skills-library/excalidraw-diagrams/CLAUDE.md +57 -0
- package/skills-library/excalidraw-diagrams/LICENSE +21 -0
- package/skills-library/excalidraw-diagrams/README.md +178 -0
- package/skills-library/excalidraw-diagrams/SKILL.md +715 -0
- package/skills-library/form-solutions/BUTTON_TYPE_FORM_SUBMISSION.md +336 -0
- package/skills-library/form-solutions/FILLABLE_PDF_IMPLEMENTATION.md +226 -0
- package/skills-library/form-solutions/SURVEYJS_QUESTIONNAIRE_SYSTEM.md +367 -0
- package/skills-library/form-solutions/tiptap-minimal-setup.md +690 -0
- package/skills-library/frontend/scholarly-classification-bubble-map.md +149 -0
- package/skills-library/infrastructure/ci-cd-pipeline-builder.md +517 -0
- package/skills-library/infrastructure/observability-designer.md +264 -0
- package/skills-library/infrastructure/performance-profiler.md +621 -0
- package/skills-library/installer-wizard-patterns.md +249 -0
- package/skills-library/integrations/CLAUDE_CODE_TOKEN_ANALYTICS.md +160 -0
- package/skills-library/integrations/CONFIGURABLE_AI_PROVIDER_SELECTION.md +728 -0
- package/skills-library/integrations/SOCKET_IO_BROADCAST_ALL_VS_ROOM.md +141 -0
- package/skills-library/integrations/VIRTUAL_MEETINGS_IMPLEMENTATION.md +374 -0
- package/skills-library/integrations/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/integrations/ai-ml/GEMINI_AI_RAG_PIPELINE_COMPLETE_GUIDE.md +195 -0
- package/skills-library/integrations/ai-ml/GEMINI_IMAGE_GENERATION_SETUP.md +64 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/ghost-creator-monetization-pattern.md +454 -0
- package/skills-library/integrations/headless-cms-architecture.md +484 -0
- package/skills-library/integrations/headless-cms-stack-selection.md +183 -0
- package/skills-library/integrations/payload-cms-patterns.md +674 -0
- package/skills-library/integrations/realtimestt-openwakeword-cuda-windows.md +229 -0
- package/skills-library/integrations/rss-podcast-integration.md +300 -0
- package/skills-library/integrations/wordpress/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/youtube/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/youtube/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/youtube/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/marketing/campaign-analytics.md +97 -0
- package/skills-library/marketing/content-creator.md +105 -0
- package/skills-library/marketing/marketing-strategy-pmm.md +94 -0
- package/skills-library/marketing/social-media-analyzer.md +81 -0
- package/skills-library/methodology/ADVANCED_ORCHESTRATION_PATTERNS.md +401 -0
- package/skills-library/methodology/AGENT_SELF_IMPROVEMENT_LOOP.md +179 -0
- package/skills-library/methodology/BREATH_BASED_PARALLEL_EXECUTION.md +1 -1
- package/skills-library/methodology/CLEANSING_CYCLE.md +358 -0
- package/skills-library/methodology/CONFIDENCE_ANNOTATION_PATTERN.md +143 -0
- package/skills-library/methodology/CRITICAL_PATTERNS_DOCUMENTATION_COMPLETE.md +204 -0
- package/skills-library/methodology/DELIVERABLES_SUMMARY.md +341 -0
- package/skills-library/methodology/DIFFICULTY_AWARE_AGENT_ROUTING.md +252 -0
- package/skills-library/methodology/EVOLUTIONARY_SKILL_SYNTHESIS.md +219 -0
- package/skills-library/methodology/GLOMERULUS_DECISION_GATE.md +223 -0
- package/skills-library/methodology/HIBERNATION_SYSTEM.md +231 -0
- package/skills-library/methodology/INSTRUMENTATION_OVER_RESTRICTION.md +192 -0
- package/skills-library/methodology/MASTER_COMPLETION_SUMMARY.md +444 -0
- package/skills-library/methodology/MASTER_SESSION_COMPLETION.md +743 -0
- package/skills-library/methodology/MERN_QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/ORGAN_AGENT_MAPPING.md +177 -0
- package/skills-library/methodology/PARALLEL_WAVE_BASED_REFACTORING.md +440 -0
- package/skills-library/methodology/QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/SDFT_ONPOLICY_SELF_DISTILLATION.md +186 -0
- package/skills-library/methodology/SELF_QUESTIONING_TASK_GENERATION.md +270 -0
- package/skills-library/methodology/SESSION_COMPLETION_SUMMARY.md +304 -0
- package/skills-library/methodology/SESSION_SUMMARY.md +432 -0
- package/skills-library/methodology/WARRIOR_WORKFLOW_DEBUGGING_PROTOCOL.md +252 -0
- package/skills-library/methodology/tech-debt-tracker.md +570 -0
- package/skills-library/parallel-debug/SKILL.md +60 -0
- package/skills-library/patterns-standards/API_PATTERN_FIX_SUMMARY.md +236 -0
- package/skills-library/patterns-standards/BATCH_OPERATIONS_WITH_PROGRESS_MODAL.md +362 -0
- package/skills-library/patterns-standards/CRITICAL_CODING_PATTERNS.md +639 -0
- package/skills-library/patterns-standards/DARK_MODE_MODAL_VISIBILITY.md +258 -0
- package/skills-library/patterns-standards/ERROR_RESILIENCE_IMPLEMENTATION.md +375 -0
- package/skills-library/patterns-standards/ES_MODULE_IMPORT_HOISTING_DOTENV.md +298 -0
- package/skills-library/patterns-standards/NESTED_BACKDROP_FILTER_CSS_ARTIFACT_FIX.md +76 -0
- package/skills-library/patterns-standards/ORDERED_DETECTOR_PIPELINE_GRACEFUL_FALLBACK.md +333 -0
- package/skills-library/patterns-standards/PHASE_IMPORT_ERROR_DEBUGGING.md +271 -0
- package/skills-library/patterns-standards/PYNPUT_GLOBAL_HOTKEY_VK_MATCHING.md +252 -0
- package/skills-library/patterns-standards/REACT_USEEFFECT_CASCADE_RESET_FIX.md +132 -0
- package/skills-library/patterns-standards/SUBMENU_HOVER_DROPDOWN_PATTERN.md +225 -0
- package/skills-library/patterns-standards/TAILWIND_TEXT_VISIBILITY_OVERRIDE.md +322 -0
- package/skills-library/patterns-standards/THEME_AWARE_CSS_VARIABLES_PATTERN.md +209 -0
- package/skills-library/patterns-standards/THEME_USER_OBJECT_PROPERTY_NAMING.md +194 -0
- package/skills-library/patterns-standards/TOOLTIP_BLOCKING_CLICKS_FIX.md +267 -0
- package/skills-library/patterns-standards/claude-code-plugin-structure.md +235 -0
- package/skills-library/patterns-standards/react-i18next-setup.md +429 -0
- package/skills-library/patterns-standards/thesys-c1-generative-ui-integration.md +967 -0
- package/skills-library/plugin-development/CLAUDE_CODE_COMMAND_REGISTRATION_SILENT_FAILURE.md +315 -0
- package/skills-library/plugin-development/plugin-command-namespace-vs-global.md +390 -0
- package/skills-library/plugin-development/plugin-doc-auto-generation.md +172 -0
- package/skills-library/security/GITHUB_REPO_SECURITY_AUDIT.md +115 -0
- package/skills-library/security/admin-deletion-safety.md +396 -0
- package/skills-library/security/application-vuln-patterns.md +477 -0
- package/skills-library/security/env-secrets-manager.md +686 -0
- package/skills-library/security/secure-ai-application-templates.md +347 -0
- package/skills-library/security/sql-injection-prevention-postgresjs.md +151 -0
- package/skills-library/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/system-context/POWERSHELL_BASH_INTEROP.md +82 -0
- package/skills-library/system-context/SERVICE_LIFECYCLE_MANAGEMENT.md +119 -0
- package/skills-library/system-context/SKILL.md +40 -0
- package/skills-library/system-context/WINDOWS_DEV_ENVIRONMENT.md +73 -0
- package/skills-library/testing/E2E_PLAYWRIGHT_PATTERNS.md +99 -0
- package/skills-library/testing/INTEGRATION_TEST_STRATEGY.md +82 -0
- package/skills-library/testing/RED_GREEN_BUGFIX_GATE.md +203 -0
- package/skills-library/testing/TEST_DATA_MANAGEMENT.md +69 -0
- package/skills-library/testing/VITEST_UNIT_TEST_PATTERNS.md +75 -0
- package/skills-library/testing/playwright-api-security-tests.md +202 -0
- package/skills-library/toolbox/SKILL.md +84 -0
- package/skills-library/toolbox/code-graph-and-web-scraping-mcps.md +237 -0
- package/skills-library/ui-ux-pro-max/ACCESSIBILITY_ESSENTIALS.md +115 -0
- package/skills-library/ui-ux-pro-max/DESIGN_SYSTEM_SCAFFOLDING.md +133 -0
- package/skills-library/ui-ux-pro-max/RESPONSIVE_LAYOUT_PATTERNS.md +119 -0
- package/skills-library/ui-ux-pro-max/SKILL.md +386 -0
- package/skills-library/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills-library/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills-library/ui-ux-pro-max/data/products.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills-library/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills-library/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills-library/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills-library/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills-library/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills-library/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills-library/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills-library/wordpress-style-theme-components.md +1526 -0
- package/templates/ASSUMPTIONS.md +1 -1
- package/templates/DECISION_LOG.md +0 -1
- package/templates/phase-prompt.md +1 -1
- package/templates/phoenix-comparison.md +6 -6
- package/templates/skill-api-integration.md +106 -0
- package/templates/skill-architecture-pattern.md +92 -0
- package/templates/skill-debug-pattern.md +98 -0
- package/templates/skill-devops-recipe.md +107 -0
- package/templates/skill-general.md +65 -0
- package/templates/skill-ui-component.md +113 -0
- package/tools/uat-runner.py +179 -0
- package/version.json +7 -3
- package/workflows/handoff-session.md +2 -2
- package/workflows/new-project.md +2 -2
- package/workflows/plan-phase.md +1 -1
- package/.claude-plugin/plugin.json +0 -64
- package/skills-library/_general/methodology/LIVE_BREADCRUMB_PROTOCOL.md +0 -242
- package/skills-library/_general/methodology/llm-judge-memory-crud.md +0 -241
- package/skills-library/methodology/REFLEXION_MEMORY_PATTERN.md +0 -183
- package/skills-library/methodology/RESEARCH_BACKED_WORKFLOW_UPGRADE.md +0 -263
- package/skills-library/methodology/SABBATH_REST_PATTERN.md +0 -267
- package/skills-library/methodology/STONE_AND_SCAFFOLD.md +0 -220
- package/skills-library/specialists/api-architecture/api-designer.md +0 -49
- package/skills-library/specialists/api-architecture/graphql-architect.md +0 -49
- package/skills-library/specialists/api-architecture/mcp-developer.md +0 -51
- package/skills-library/specialists/api-architecture/microservices-architect.md +0 -50
- package/skills-library/specialists/api-architecture/websocket-engineer.md +0 -48
- package/skills-library/specialists/backend/django-expert.md +0 -52
- package/skills-library/specialists/backend/fastapi-expert.md +0 -52
- package/skills-library/specialists/backend/laravel-specialist.md +0 -52
- package/skills-library/specialists/backend/nestjs-expert.md +0 -51
- package/skills-library/specialists/backend/rails-expert.md +0 -53
- package/skills-library/specialists/backend/spring-boot-engineer.md +0 -56
- package/skills-library/specialists/data-ml/fine-tuning-expert.md +0 -48
- package/skills-library/specialists/data-ml/ml-pipeline.md +0 -47
- package/skills-library/specialists/data-ml/pandas-pro.md +0 -47
- package/skills-library/specialists/data-ml/rag-architect.md +0 -51
- package/skills-library/specialists/data-ml/spark-engineer.md +0 -47
- package/skills-library/specialists/frontend/angular-architect.md +0 -52
- package/skills-library/specialists/frontend/flutter-expert.md +0 -51
- package/skills-library/specialists/frontend/nextjs-developer.md +0 -54
- package/skills-library/specialists/frontend/react-native-expert.md +0 -50
- package/skills-library/specialists/frontend/vue-expert.md +0 -51
- package/skills-library/specialists/infrastructure/chaos-engineer.md +0 -74
- package/skills-library/specialists/infrastructure/cloud-architect.md +0 -70
- package/skills-library/specialists/infrastructure/database-optimizer.md +0 -64
- package/skills-library/specialists/infrastructure/devops-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/kubernetes-specialist.md +0 -52
- package/skills-library/specialists/infrastructure/monitoring-expert.md +0 -70
- package/skills-library/specialists/infrastructure/sre-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/terraform-engineer.md +0 -51
- package/skills-library/specialists/languages/cpp-pro.md +0 -74
- package/skills-library/specialists/languages/csharp-developer.md +0 -69
- package/skills-library/specialists/languages/dotnet-core-expert.md +0 -54
- package/skills-library/specialists/languages/golang-pro.md +0 -51
- package/skills-library/specialists/languages/java-architect.md +0 -49
- package/skills-library/specialists/languages/javascript-pro.md +0 -68
- package/skills-library/specialists/languages/kotlin-specialist.md +0 -68
- package/skills-library/specialists/languages/php-pro.md +0 -49
- package/skills-library/specialists/languages/python-pro.md +0 -52
- package/skills-library/specialists/languages/react-expert.md +0 -51
- package/skills-library/specialists/languages/rust-engineer.md +0 -50
- package/skills-library/specialists/languages/sql-pro.md +0 -56
- package/skills-library/specialists/languages/swift-expert.md +0 -69
- package/skills-library/specialists/languages/typescript-pro.md +0 -51
- package/skills-library/specialists/platform/atlassian-mcp.md +0 -52
- package/skills-library/specialists/platform/embedded-systems.md +0 -53
- package/skills-library/specialists/platform/game-developer.md +0 -53
- package/skills-library/specialists/platform/salesforce-developer.md +0 -53
- package/skills-library/specialists/platform/shopify-expert.md +0 -49
- package/skills-library/specialists/platform/wordpress-pro.md +0 -49
- package/skills-library/specialists/quality/code-documenter.md +0 -51
- package/skills-library/specialists/quality/code-reviewer.md +0 -67
- package/skills-library/specialists/quality/debugging-wizard.md +0 -51
- package/skills-library/specialists/quality/fullstack-guardian.md +0 -51
- package/skills-library/specialists/quality/legacy-modernizer.md +0 -50
- package/skills-library/specialists/quality/playwright-expert.md +0 -65
- package/skills-library/specialists/quality/spec-miner.md +0 -56
- package/skills-library/specialists/quality/test-master.md +0 -65
- package/skills-library/specialists/security/secure-code-guardian.md +0 -55
- package/skills-library/specialists/security/security-reviewer.md +0 -53
- package/skills-library/specialists/workflow/architecture-designer.md +0 -53
- package/skills-library/specialists/workflow/cli-developer.md +0 -70
- package/skills-library/specialists/workflow/feature-forge.md +0 -65
- package/skills-library/specialists/workflow/prompt-engineer.md +0 -54
- package/skills-library/specialists/workflow/the-fool.md +0 -62
- /package/skills-library/{performance → _general/performance}/cache-augmented-generation.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/FAILURE_TAXONOMY_CLASSIFICATION.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/THREE_AGENT_HYPOTHESIS_DEBUGGING.md +0 -0
|
@@ -0,0 +1,1526 @@
|
|
|
1
|
+
# WordPress-Style Theme Component System - Complete Implementation Guide
|
|
2
|
+
|
|
3
|
+
**Created:** January 17, 2026
|
|
4
|
+
**Updated:** January 18, 2026
|
|
5
|
+
**Status:** ✅ COMPLETE & TESTED
|
|
6
|
+
|
|
7
|
+
> ⚠️ **IMPORTANT**: This document is now SUPERSEDED by the comprehensive guide:
|
|
8
|
+
> **`docs/THEME_COMPLETE_DEVELOPER_GUIDE.md`** - Single Source of Truth for theme development
|
|
9
|
+
>
|
|
10
|
+
> This file is kept for reference but the new guide includes all content plus:
|
|
11
|
+
> - Tailwind CSS v4 production fixes
|
|
12
|
+
> - Manual CSS fallback requirements
|
|
13
|
+
> - Updated deployment procedures
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🎯 Problem Statement
|
|
18
|
+
|
|
19
|
+
**Challenge:** Traditional theme systems only change colors/fonts - need WordPress-style complete UI transformation
|
|
20
|
+
**Goal:** Allow themes to override ANY component (Header, Footer, Hero, etc.) without modifying core code
|
|
21
|
+
**Solution:** Dynamic component loading with theme-specific overrides via a centralized ThemeManager
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🏗️ Architecture Overview
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
29
|
+
│ Theme System Flow │
|
|
30
|
+
├─────────────────────────────────────────────────────────────────────┤
|
|
31
|
+
│ │
|
|
32
|
+
│ 1. App Startup │
|
|
33
|
+
│ └─> ThemeManager.loadTheme('celestial') │
|
|
34
|
+
│ └─> Loads theme.json for config │
|
|
35
|
+
│ └─> Loads components/index.js for overrides │
|
|
36
|
+
│ └─> Registers overrides in componentOverrides Map │
|
|
37
|
+
│ │
|
|
38
|
+
│ 2. Component Resolution (via ThemeContext) │
|
|
39
|
+
│ └─> getComponent('Header') called │
|
|
40
|
+
│ └─> Check componentOverrides Map │
|
|
41
|
+
│ └─> Return theme's Header OR fallback to default │
|
|
42
|
+
│ │
|
|
43
|
+
│ 3. MainLayout renders │
|
|
44
|
+
│ └─> Uses resolved Header, Footer from getComponent() │
|
|
45
|
+
│ └─> Wrapped in React.Suspense for lazy loading │
|
|
46
|
+
│ │
|
|
47
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📁 File Structure
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
project-root/
|
|
56
|
+
├── client/
|
|
57
|
+
│ ├── src/
|
|
58
|
+
│ │ ├── services/
|
|
59
|
+
│ │ │ └── ThemeManager.js # Core theme loading logic
|
|
60
|
+
│ │ ├── contexts/
|
|
61
|
+
│ │ │ └── ThemeContext.jsx # React context for themes
|
|
62
|
+
│ │ ├── layouts/
|
|
63
|
+
│ │ │ └── MainLayout.jsx # Uses component resolver
|
|
64
|
+
│ │ └── components/
|
|
65
|
+
│ │ └── layout/
|
|
66
|
+
│ │ ├── Header.jsx # Default Header
|
|
67
|
+
│ │ └── Footer.jsx # Default Footer
|
|
68
|
+
│ └── vite.config.js # Alias and fs.allow config
|
|
69
|
+
│
|
|
70
|
+
└── themes/
|
|
71
|
+
└── celestial/ # Example theme
|
|
72
|
+
├── theme.json # Theme metadata
|
|
73
|
+
├── components/
|
|
74
|
+
│ ├── index.js # Component exports (CRITICAL)
|
|
75
|
+
│ └── layout/
|
|
76
|
+
│ ├── Header.jsx # Theme-specific Header
|
|
77
|
+
│ └── Footer.jsx # Theme-specific Footer
|
|
78
|
+
├── puck/
|
|
79
|
+
│ └── index.jsx # Puck editor components
|
|
80
|
+
└── styles/
|
|
81
|
+
└── theme.css # CSS variables & animations
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 🔧 Core Implementation
|
|
87
|
+
|
|
88
|
+
### 1. Vite Configuration (vite.config.js)
|
|
89
|
+
|
|
90
|
+
**CRITICAL:** Themes live outside `client/src`, so Vite needs special config:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
import { defineConfig } from 'vite';
|
|
94
|
+
import react from '@vitejs/plugin-react';
|
|
95
|
+
import path from 'path';
|
|
96
|
+
|
|
97
|
+
export default defineConfig({
|
|
98
|
+
plugins: [react()],
|
|
99
|
+
resolve: {
|
|
100
|
+
alias: {
|
|
101
|
+
'@': path.resolve(__dirname, './src'),
|
|
102
|
+
// CRITICAL: Alias for themes folder
|
|
103
|
+
'@themes': path.resolve(__dirname, '../themes'),
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
server: {
|
|
107
|
+
fs: {
|
|
108
|
+
// CRITICAL: Allow Vite to serve files from themes folder
|
|
109
|
+
allow: ['..'],
|
|
110
|
+
},
|
|
111
|
+
proxy: {
|
|
112
|
+
// Optional: Serve theme assets
|
|
113
|
+
'/themes': {
|
|
114
|
+
target: 'http://localhost:5173',
|
|
115
|
+
rewrite: (path) => path.replace(/^\/themes/, '/../themes'),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2. ThemeManager Service (ThemeManager.js)
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
class ThemeManager {
|
|
126
|
+
constructor() {
|
|
127
|
+
this.currentTheme = null;
|
|
128
|
+
this.themeConfig = null;
|
|
129
|
+
this.componentOverrides = new Map();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Dynamic imports using Vite's import.meta.glob
|
|
133
|
+
async loadThemeComponents(themeName) {
|
|
134
|
+
try {
|
|
135
|
+
// Use @themes alias to access themes folder
|
|
136
|
+
const themeModules = import.meta.glob('@themes/*/components/index.js');
|
|
137
|
+
const modulePath = `../themes/${themeName}/components/index.js`;
|
|
138
|
+
|
|
139
|
+
// Find the matching module path (glob returns relative to project root)
|
|
140
|
+
const matchingKey = Object.keys(themeModules).find(key =>
|
|
141
|
+
key.includes(`/${themeName}/components/index.js`)
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
if (matchingKey && themeModules[matchingKey]) {
|
|
145
|
+
const module = await themeModules[matchingKey]();
|
|
146
|
+
|
|
147
|
+
// Register each exported component
|
|
148
|
+
if (module.Header) this.componentOverrides.set('Header', module.Header);
|
|
149
|
+
if (module.Footer) this.componentOverrides.set('Footer', module.Footer);
|
|
150
|
+
if (module.Hero) this.componentOverrides.set('Hero', module.Hero);
|
|
151
|
+
|
|
152
|
+
console.log(`[ThemeManager] Loaded ${this.componentOverrides.size} component overrides`);
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.warn(`[ThemeManager] No components found for theme: ${themeName}`, error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Get component with fallback to default
|
|
160
|
+
getComponent(componentName) {
|
|
161
|
+
return this.componentOverrides.get(componentName) || null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Load Puck editor components (MUST use .jsx extension)
|
|
165
|
+
async loadPuckComponents(themeName) {
|
|
166
|
+
const puckModules = import.meta.glob('@themes/*/puck/index.jsx');
|
|
167
|
+
// ... similar pattern
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const themeManager = new ThemeManager();
|
|
172
|
+
export default themeManager;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 3. Theme Context (ThemeContext.jsx)
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
import React, { createContext, useContext, useState, useEffect } from 'react';
|
|
179
|
+
import themeManager from '../services/ThemeManager';
|
|
180
|
+
|
|
181
|
+
const ThemeContext = createContext();
|
|
182
|
+
|
|
183
|
+
export const ThemeProvider = ({ children }) => {
|
|
184
|
+
const [theme, setTheme] = useState(null);
|
|
185
|
+
const [loading, setLoading] = useState(true);
|
|
186
|
+
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
const initTheme = async () => {
|
|
189
|
+
// Load from localStorage or API
|
|
190
|
+
const savedTheme = localStorage.getItem('activeTheme') || 'default';
|
|
191
|
+
await themeManager.loadTheme(savedTheme);
|
|
192
|
+
setTheme(themeManager.themeConfig);
|
|
193
|
+
setLoading(false);
|
|
194
|
+
};
|
|
195
|
+
initTheme();
|
|
196
|
+
}, []);
|
|
197
|
+
|
|
198
|
+
// CRITICAL: This is what components use to get overridden components
|
|
199
|
+
const getComponent = (componentName) => {
|
|
200
|
+
return themeManager.getComponent(componentName);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<ThemeContext.Provider value={{ theme, loading, getComponent, setTheme }}>
|
|
205
|
+
{children}
|
|
206
|
+
</ThemeContext.Provider>
|
|
207
|
+
);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const useTheme = () => useContext(ThemeContext);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 4. MainLayout with Component Resolver (MainLayout.jsx)
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
import React, { Suspense } from 'react';
|
|
217
|
+
import { useTheme } from '../contexts/ThemeContext';
|
|
218
|
+
|
|
219
|
+
// Default components (fallbacks)
|
|
220
|
+
import DefaultHeader from '../components/layout/Header';
|
|
221
|
+
import DefaultFooter from '../components/layout/Footer';
|
|
222
|
+
|
|
223
|
+
const MainLayout = ({ children }) => {
|
|
224
|
+
const { getComponent } = useTheme();
|
|
225
|
+
|
|
226
|
+
// CRITICAL: Resolve components with fallback
|
|
227
|
+
const Header = getComponent('Header') || DefaultHeader;
|
|
228
|
+
const Footer = getComponent('Footer') || DefaultFooter;
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div className="min-h-screen flex flex-col">
|
|
232
|
+
{/* CRITICAL: Suspense handles lazy-loaded theme components */}
|
|
233
|
+
<Suspense fallback={<div className="h-16 bg-gray-100 animate-pulse" />}>
|
|
234
|
+
<Header />
|
|
235
|
+
</Suspense>
|
|
236
|
+
|
|
237
|
+
<main className="flex-1">
|
|
238
|
+
{children}
|
|
239
|
+
</main>
|
|
240
|
+
|
|
241
|
+
<Suspense fallback={<div className="h-64 bg-gray-100 animate-pulse" />}>
|
|
242
|
+
<Footer />
|
|
243
|
+
</Suspense>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export default MainLayout;
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 5. Theme Component Exports (themes/celestial/components/index.js)
|
|
252
|
+
|
|
253
|
+
**CRITICAL:** This file is what ThemeManager loads - exports must match expected names:
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
// Re-export all theme components
|
|
257
|
+
export { default as Header } from './layout/Header';
|
|
258
|
+
export { default as Footer } from './layout/Footer';
|
|
259
|
+
export { default as Hero } from './Hero';
|
|
260
|
+
|
|
261
|
+
// Export metadata for discovery
|
|
262
|
+
export const themeComponents = {
|
|
263
|
+
Header: { description: 'Luxury transparent-to-solid header' },
|
|
264
|
+
Footer: { description: 'Four-column footer with gold accents' },
|
|
265
|
+
Hero: { description: 'Multiple hero variants with animations' },
|
|
266
|
+
};
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 🚨 Critical Gotchas & Solutions
|
|
272
|
+
|
|
273
|
+
### 1. JSX Files Must Use .jsx Extension
|
|
274
|
+
|
|
275
|
+
**Problem:** Vite's `import.meta.glob` doesn't parse JSX in `.js` files
|
|
276
|
+
|
|
277
|
+
**Error:**
|
|
278
|
+
```
|
|
279
|
+
[vite] Internal server error: Failed to parse source for import analysis
|
|
280
|
+
because the content contains invalid JS syntax. If you are using JSX,
|
|
281
|
+
make sure to name the file with the .jsx extension.
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Solution:**
|
|
285
|
+
- Rename files with JSX to `.jsx`
|
|
286
|
+
- Update glob pattern: `import.meta.glob('@themes/*/puck/index.jsx')`
|
|
287
|
+
|
|
288
|
+
### 2. External vs Internal Links in Theme Components
|
|
289
|
+
|
|
290
|
+
**Problem:** Using `<Link to="/external-url">` breaks for external URLs
|
|
291
|
+
|
|
292
|
+
**Solution:** Create helper functions:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
const isExternalLink = (url) => {
|
|
296
|
+
if (!url) return false;
|
|
297
|
+
return url.startsWith('http://') ||
|
|
298
|
+
url.startsWith('https://') ||
|
|
299
|
+
url.startsWith('//');
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// In render:
|
|
303
|
+
{isExternalLink(item.url) ? (
|
|
304
|
+
<a href={item.url} target="_blank" rel="noopener noreferrer">
|
|
305
|
+
{item.label}
|
|
306
|
+
</a>
|
|
307
|
+
) : (
|
|
308
|
+
<Link to={item.url}>{item.label}</Link>
|
|
309
|
+
)}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 3. Dashboard Route Paths
|
|
313
|
+
|
|
314
|
+
**Problem:** Links like `/my-courses` get caught by CMS PageRenderer, causing 404
|
|
315
|
+
|
|
316
|
+
**Solution:** Use full dashboard paths:
|
|
317
|
+
```javascript
|
|
318
|
+
// ❌ WRONG - caught by CMS
|
|
319
|
+
<Link to="/my-courses">My Courses</Link>
|
|
320
|
+
|
|
321
|
+
// ✅ CORRECT - matches React Router
|
|
322
|
+
<Link to="/dashboard/my-courses">My Courses</Link>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Standard dashboard routes:**
|
|
326
|
+
- `/dashboard` - Main dashboard
|
|
327
|
+
- `/dashboard/my-courses` - Enrolled courses
|
|
328
|
+
- `/dashboard/orders` - Order history
|
|
329
|
+
- `/dashboard/settings` - User settings
|
|
330
|
+
|
|
331
|
+
### 4. Vite fs.allow Error
|
|
332
|
+
|
|
333
|
+
**Problem:** Vite refuses to serve files outside project root
|
|
334
|
+
|
|
335
|
+
**Error:**
|
|
336
|
+
```
|
|
337
|
+
The request url "/themes/celestial/..." is outside of Vite serving allow list.
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Solution:** Add to vite.config.js:
|
|
341
|
+
```javascript
|
|
342
|
+
server: {
|
|
343
|
+
fs: {
|
|
344
|
+
allow: ['..'], // Allow parent directory
|
|
345
|
+
},
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 5. Dynamic Import Path Resolution
|
|
350
|
+
|
|
351
|
+
**Problem:** `import.meta.glob` paths must be statically analyzable
|
|
352
|
+
|
|
353
|
+
**Solution:** Use the alias in glob pattern:
|
|
354
|
+
```javascript
|
|
355
|
+
// ✅ WORKS - Vite can analyze at build time
|
|
356
|
+
const modules = import.meta.glob('@themes/*/components/index.js');
|
|
357
|
+
|
|
358
|
+
// ❌ FAILS - Dynamic string
|
|
359
|
+
const themeName = 'celestial';
|
|
360
|
+
const modules = import.meta.glob(`@themes/${themeName}/components/index.js`);
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 6. CSS Cascade Layers & Tailwind v4 Conflict (CRITICAL)
|
|
364
|
+
|
|
365
|
+
**Problem:** Theme CSS universal selectors override Tailwind utility classes
|
|
366
|
+
|
|
367
|
+
**Background:** Tailwind CSS v4 uses CSS `@layer` directives (base, components, utilities). In CSS Cascade Layers, **unlayered CSS has HIGHER precedence than layered CSS**, regardless of specificity.
|
|
368
|
+
|
|
369
|
+
**Symptoms:**
|
|
370
|
+
- `mx-auto` doesn't center content (computed margin is `0px` instead of `auto`)
|
|
371
|
+
- `px-*`, `py-*` padding utilities are ignored
|
|
372
|
+
- Content appears left-aligned instead of centered
|
|
373
|
+
- Tailwind classes seem to have no effect
|
|
374
|
+
|
|
375
|
+
**Root Cause:**
|
|
376
|
+
```css
|
|
377
|
+
/* ❌ BAD - Theme CSS (unlayered) */
|
|
378
|
+
* {
|
|
379
|
+
margin: 0;
|
|
380
|
+
padding: 0;
|
|
381
|
+
box-sizing: border-box;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
This unlayered CSS **beats** Tailwind's layered `.mx-auto { margin-left: auto; margin-right: auto; }` even though `.mx-auto` has higher specificity than `*`.
|
|
386
|
+
|
|
387
|
+
**Solution:**
|
|
388
|
+
```css
|
|
389
|
+
/* ✅ GOOD - Only keep box-sizing, let Tailwind's Preflight handle resets */
|
|
390
|
+
* {
|
|
391
|
+
box-sizing: border-box;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/* Note: Tailwind's Preflight (in @layer base) provides proper CSS reset */
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Debug Steps:**
|
|
398
|
+
1. Check computed styles in DevTools - if `marginLeft: 0px` on elements with `mx-auto` class
|
|
399
|
+
2. Search theme CSS for `* {` or universal selectors with `margin` or `padding`
|
|
400
|
+
3. Remove `margin: 0` and `padding: 0` from universal selectors
|
|
401
|
+
4. Test centering works after change
|
|
402
|
+
|
|
403
|
+
**Prevention:** Never use CSS resets in theme files - Tailwind's Preflight handles this. Only use specific selectors in theme CSS.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 🤖 AI Agent Theme Generation Checklist
|
|
408
|
+
|
|
409
|
+
**MANDATORY for AI agents generating themes. Verify BEFORE output.**
|
|
410
|
+
|
|
411
|
+
### ⚠️ CRITICAL: Component Compatibility Layer (CHECK FGTAT)
|
|
412
|
+
|
|
413
|
+
This is the **#1 cause of production build failures**. Theme components live OUTSIDE the client workspace, so Vite/Rollup CANNOT resolve npm packages or path aliases.
|
|
414
|
+
|
|
415
|
+
- [ ] **NO npm package imports** - Search for `from 'react-router-dom'`, `from 'react-redux'`, `from 'axios'`
|
|
416
|
+
- [ ] **NO path alias imports** - Search for `from '@/`
|
|
417
|
+
- [ ] **Uses local Link component** - `const Link = ({ to, children }) => <a href={to}>{children}</a>;`
|
|
418
|
+
- [ ] **Uses useAuth() hook** - Reads from `window.__LMS_AUTH__` global
|
|
419
|
+
- [ ] **Uses useThemeSettings() hook** - Reads from `window.__LMS_THEME_SETTINGS__` global
|
|
420
|
+
- [ ] **Uses performLogout()** - fetch + localStorage, not Redux dispatch
|
|
421
|
+
- [ ] **Uses fetch() for API calls** - NOT axios
|
|
422
|
+
|
|
423
|
+
### theme.json Requirements
|
|
424
|
+
- [ ] Has `name` (lowercase-slug), `displayName`, `version`, `description`
|
|
425
|
+
- [ ] `colors` object at ROOT level (NOT under `themeSettings`)
|
|
426
|
+
- [ ] All 8 color keys present: `primary`, `secondary`, `accent`, `background`, `surface`, `text`, `muted`, `border`
|
|
427
|
+
- [ ] Color values are HEX STRINGS like `"#4F46E5"` (NOT objects)
|
|
428
|
+
- [ ] NO `themeSettings`, `entryPoint`, `screenshot`, or `supports` array
|
|
429
|
+
|
|
430
|
+
### theme.css Requirements
|
|
431
|
+
- [ ] Contains ONLY `* { box-sizing: border-box; }`
|
|
432
|
+
- [ ] NO `margin: 0` or `padding: 0` on universal selector
|
|
433
|
+
- [ ] NO CSS reset imports (normalize.css, reset.css)
|
|
434
|
+
- [ ] NO `html, body { margin: 0; padding: 0; }`
|
|
435
|
+
|
|
436
|
+
### File Structure Requirements
|
|
437
|
+
- [ ] `theme.json` at root
|
|
438
|
+
- [ ] `styles/theme.css` exists
|
|
439
|
+
- [ ] `components/index.js` exists (can export empty object)
|
|
440
|
+
- [ ] `preview.png` is real 400x300 image (NOT 1x1 placeholder)
|
|
441
|
+
- [ ] NO `index.jsx` file
|
|
442
|
+
- [ ] NO `screenshot.png` file
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## 📋 Theme Component Checklist
|
|
447
|
+
|
|
448
|
+
When creating a new theme component:
|
|
449
|
+
|
|
450
|
+
- [ ] **Include compatibility layer** at top of file (useAuth, useThemeSettings, Link with navigation delay, performLogout)
|
|
451
|
+
- [ ] Create in `themes/[theme-name]/components/` folder
|
|
452
|
+
- [ ] Use `.jsx` extension if file contains JSX
|
|
453
|
+
- [ ] Export from `components/index.js`
|
|
454
|
+
- [ ] Match export name to expected component (Header, Footer, Hero)
|
|
455
|
+
- [ ] Use local `<Link>` wrapper with 100ms setTimeout delay, NOT react-router-dom Link
|
|
456
|
+
- [ ] Use `fetch()` for API calls, NOT axios
|
|
457
|
+
|
|
458
|
+
**Mobile Sidebar (6 Requirements):**
|
|
459
|
+
- [ ] **`lg:hidden` on toggle button** - Hamburger menu hidden on desktop
|
|
460
|
+
- [ ] **`lg:hidden` on sidebar panel** - Slide-out menu hidden on desktop
|
|
461
|
+
- [ ] **`lg:hidden` on backdrop** - Dark overlay hidden on desktop
|
|
462
|
+
- [ ] **Transform classes** - `translate-x-full` and `translate-x-0` in component
|
|
463
|
+
- [ ] **Navigation delay** - Link component has 100ms setTimeout before window.location.href
|
|
464
|
+
- [ ] **Initial state** - `useState(false)` for sidebar closed on load
|
|
465
|
+
|
|
466
|
+
**Build & Test:**
|
|
467
|
+
- [ ] Test with React.Suspense for lazy loading
|
|
468
|
+
- [ ] Include responsive design (mobile sidebar, etc.)
|
|
469
|
+
- [ ] **Test production build** - Run `npm run build` to verify no resolution errors
|
|
470
|
+
- [ ] **Verify on both desktop and mobile** - No duplicate menus, sidebar closes on link click
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## ⚙️ Tailwind Content Configuration (CRITICAL)
|
|
475
|
+
|
|
476
|
+
Theme files in `/themes/` folder are **outside** the default Tailwind scan path. Without proper config, theme Tailwind classes get **purged** in production!
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
// client/tailwind.config.js - MUST include themes folder
|
|
480
|
+
export default {
|
|
481
|
+
content: [
|
|
482
|
+
"./index.html",
|
|
483
|
+
"./src/**/*.{js,ts,jsx,tsx,css}",
|
|
484
|
+
"../themes/**/*.{js,jsx,ts,tsx}", // ✅ CRITICAL!
|
|
485
|
+
],
|
|
486
|
+
};
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**Symptoms of missing config:**
|
|
490
|
+
- `lg:hidden` doesn't hide elements on desktop
|
|
491
|
+
- Responsive classes work in dev but break in production
|
|
492
|
+
- Mobile sidebar visible on all screen sizes
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## 📱 Mobile Sidebar Responsiveness (CRITICAL)
|
|
497
|
+
|
|
498
|
+
### The 4 Mobile Sidebar Requirements
|
|
499
|
+
|
|
500
|
+
When implementing mobile slide-out navigation, you MUST follow these 4 requirements to ensure proper functionality:
|
|
501
|
+
|
|
502
|
+
#### 1. Three Elements Rule - ALL need `lg:hidden`
|
|
503
|
+
|
|
504
|
+
**ALL THREE elements must have `lg:hidden`** class:
|
|
505
|
+
|
|
506
|
+
```jsx
|
|
507
|
+
{/* 1. Toggle button - MUST have lg:hidden */}
|
|
508
|
+
<button
|
|
509
|
+
className="lg:hidden p-2"
|
|
510
|
+
onClick={() => setSidebarOpen(!sidebarOpen)}
|
|
511
|
+
aria-label="Toggle navigation"
|
|
512
|
+
>
|
|
513
|
+
<MenuIcon />
|
|
514
|
+
</button>
|
|
515
|
+
|
|
516
|
+
{/* 2. Sidebar panel - MUST have lg:hidden */}
|
|
517
|
+
<div className={`lg:hidden fixed top-0 right-0 h-full z-40 transition-transform duration-300 ${
|
|
518
|
+
sidebarOpen ? 'translate-x-0' : 'translate-x-full'
|
|
519
|
+
}`}>
|
|
520
|
+
{/* sidebar content with links */}
|
|
521
|
+
</div>
|
|
522
|
+
|
|
523
|
+
{/* 3. Backdrop overlay - MUST have lg:hidden */}
|
|
524
|
+
{sidebarOpen && (
|
|
525
|
+
<div
|
|
526
|
+
className="lg:hidden fixed inset-0 z-30 bg-black/50"
|
|
527
|
+
onClick={() => setSidebarOpen(false)}
|
|
528
|
+
/>
|
|
529
|
+
)}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### 2. CSS Transform Fallbacks (Tailwind v4)
|
|
533
|
+
|
|
534
|
+
**CRITICAL:** Tailwind v4 may not compile transform classes for themes folder. Add manual fallbacks:
|
|
535
|
+
|
|
536
|
+
```css
|
|
537
|
+
/* client/src/styles/theme-overrides.css */
|
|
538
|
+
.translate-x-full {
|
|
539
|
+
transform: translateX(100%) !important;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.translate-x-0 {
|
|
543
|
+
transform: translateX(0) !important;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.-translate-x-full {
|
|
547
|
+
transform: translateX(-100%) !important;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* Also add in client/src/styles/index.css for desktop responsiveness */
|
|
551
|
+
@media (min-width: 1024px) {
|
|
552
|
+
.lg\:hidden {
|
|
553
|
+
display: none !important;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Import in main.jsx:**
|
|
559
|
+
```javascript
|
|
560
|
+
import './styles/index.css';
|
|
561
|
+
import './styles/theme-overrides.css'; // Add this
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
#### 3. Link Navigation Delay (Sidebar Closing Issue)
|
|
565
|
+
|
|
566
|
+
**Problem:** Clicking menu links didn't close sidebar because browser navigated before `setSidebarOpen(false)` could execute.
|
|
567
|
+
|
|
568
|
+
**Solution:** Modified Link component with 100ms delay:
|
|
569
|
+
|
|
570
|
+
```javascript
|
|
571
|
+
const Link = ({ to, children, className, style, onClick }) => {
|
|
572
|
+
const handleClick = (e) => {
|
|
573
|
+
// Call any custom onClick handler
|
|
574
|
+
if (onClick) onClick(e);
|
|
575
|
+
|
|
576
|
+
// For internal links, delay navigation to allow sidebar to close
|
|
577
|
+
if (to && !to.startsWith('http') && !to.startsWith('//')) {
|
|
578
|
+
e.preventDefault();
|
|
579
|
+
setTimeout(() => {
|
|
580
|
+
window.location.href = to;
|
|
581
|
+
}, 100);
|
|
582
|
+
}
|
|
583
|
+
// External links navigate immediately (no preventDefault)
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
return (
|
|
587
|
+
<a
|
|
588
|
+
href={to}
|
|
589
|
+
className={className}
|
|
590
|
+
style={style}
|
|
591
|
+
onClick={handleClick}
|
|
592
|
+
>
|
|
593
|
+
{children}
|
|
594
|
+
</a>
|
|
595
|
+
);
|
|
596
|
+
};
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Usage in sidebar links:**
|
|
600
|
+
```jsx
|
|
601
|
+
<Link
|
|
602
|
+
to="/courses"
|
|
603
|
+
className="block py-2"
|
|
604
|
+
onClick={() => setSidebarOpen(false)} // This now has time to execute
|
|
605
|
+
>
|
|
606
|
+
Courses
|
|
607
|
+
</Link>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
#### 4. State Initialization
|
|
611
|
+
|
|
612
|
+
```javascript
|
|
613
|
+
const [sidebarOpen, setSidebarOpen] = useState(false); // Starts closed
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### Common Mistakes & Solutions
|
|
617
|
+
|
|
618
|
+
| Mistake | Symptom | Fix |
|
|
619
|
+
|---------|---------|-----|
|
|
620
|
+
| Missing `lg:hidden` on toggle | Hamburger menu shows on desktop | Add `lg:hidden` to button |
|
|
621
|
+
| Missing `lg:hidden` on panel | Sidebar visible on desktop | Add `lg:hidden` to sidebar div |
|
|
622
|
+
| Missing `lg:hidden` on backdrop | Dark overlay on desktop | Add `lg:hidden` to backdrop div |
|
|
623
|
+
| No transform fallback | Sidebar visible on page load (mobile) | Add `translate-x-full` CSS to theme-overrides.css |
|
|
624
|
+
| No navigation delay | Sidebar doesn't close on link click | Add 100ms setTimeout in Link onClick |
|
|
625
|
+
| Wrong initial state | Sidebar open on page load | Set `useState(false)` |
|
|
626
|
+
|
|
627
|
+
### Tailwind CSS v4 Key Differences
|
|
628
|
+
|
|
629
|
+
**IMPORTANT:** This project uses Tailwind CSS v4.1.13, which has different configuration:
|
|
630
|
+
|
|
631
|
+
- Uses `@import "tailwindcss"` (NOT `@tailwind base/components/utilities`)
|
|
632
|
+
- Content scanning via `@source` directive in CSS (NOT `tailwind.config.js`)
|
|
633
|
+
- `@source` may NOT reliably scan external folders like `/themes/`
|
|
634
|
+
- **Always add manual CSS fallbacks** for critical responsive classes
|
|
635
|
+
|
|
636
|
+
```css
|
|
637
|
+
/* client/src/styles/index.css */
|
|
638
|
+
@import "tailwindcss";
|
|
639
|
+
|
|
640
|
+
/* Tell Tailwind to scan themes folder */
|
|
641
|
+
@source "../../themes";
|
|
642
|
+
|
|
643
|
+
/* CRITICAL: Manual fallback for lg:hidden */
|
|
644
|
+
@media (min-width: 1024px) {
|
|
645
|
+
.lg\:hidden { display: none !important; }
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Testing Checklist
|
|
650
|
+
|
|
651
|
+
- [ ] Desktop (≥1024px): Only horizontal nav visible, no hamburger menu
|
|
652
|
+
- [ ] Mobile (<1024px): Only hamburger menu visible, no horizontal nav
|
|
653
|
+
- [ ] Mobile sidebar starts closed on page load
|
|
654
|
+
- [ ] Clicking hamburger opens sidebar with smooth slide-in
|
|
655
|
+
- [ ] Clicking backdrop closes sidebar
|
|
656
|
+
- [ ] Clicking link closes sidebar THEN navigates
|
|
657
|
+
- [ ] Sidebar doesn't flash visible on desktop
|
|
658
|
+
- [ ] Build succeeds without errors (`npm run build`)
|
|
659
|
+
|
|
660
|
+
### Reference Implementation
|
|
661
|
+
|
|
662
|
+
**See:** `themes/celestial/components/layout/Header.jsx` for complete working example.
|
|
663
|
+
|
|
664
|
+
**Why this matters:**
|
|
665
|
+
- Desktop (≥1024px) already has horizontal nav in `<nav className="hidden lg:flex">`
|
|
666
|
+
- Mobile sidebar without `lg:hidden` creates duplicate navigation
|
|
667
|
+
- Confusing UX with two menus visible
|
|
668
|
+
- Transform classes need manual fallbacks for Tailwind v4
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
## 🧪 Testing Theme Components
|
|
673
|
+
|
|
674
|
+
### Manual Test Steps
|
|
675
|
+
|
|
676
|
+
1. **Set active theme:**
|
|
677
|
+
```javascript
|
|
678
|
+
localStorage.setItem('activeTheme', 'celestial');
|
|
679
|
+
location.reload();
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
2. **Check browser console:**
|
|
683
|
+
```
|
|
684
|
+
[ThemeManager] Loading theme: celestial
|
|
685
|
+
[ThemeManager] Loaded 3 component overrides
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
3. **Verify component replacement:**
|
|
689
|
+
- Open React DevTools
|
|
690
|
+
- Find MainLayout
|
|
691
|
+
- Confirm Header/Footer are from theme folder
|
|
692
|
+
|
|
693
|
+
### Quick Debug Commands
|
|
694
|
+
|
|
695
|
+
```javascript
|
|
696
|
+
// In browser console:
|
|
697
|
+
import.meta.glob('@themes/*/components/index.js') // See available themes
|
|
698
|
+
themeManager.componentOverrides // See registered overrides
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
---
|
|
702
|
+
|
|
703
|
+
## 📝 Example: Creating a New Theme
|
|
704
|
+
|
|
705
|
+
### Step 1: Create folder structure
|
|
706
|
+
```
|
|
707
|
+
themes/
|
|
708
|
+
└── my-theme/
|
|
709
|
+
├── theme.json
|
|
710
|
+
├── components/
|
|
711
|
+
│ ├── index.js
|
|
712
|
+
│ └── layout/
|
|
713
|
+
│ └── Header.jsx
|
|
714
|
+
└── styles/
|
|
715
|
+
└── theme.css
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Step 2: Create theme.json
|
|
719
|
+
|
|
720
|
+
**⚠️ CRITICAL FOR AI AGENTS: Follow this EXACT format. Common mistakes break theme installation.**
|
|
721
|
+
|
|
722
|
+
#### Required Fields (ALL mandatory):
|
|
723
|
+
| Field | Format | Example |
|
|
724
|
+
|-------|--------|---------|
|
|
725
|
+
| `name` | lowercase-slug | `"my-theme"` |
|
|
726
|
+
| `displayName` | Human readable | `"My Theme"` |
|
|
727
|
+
| `version` | Semantic | `"1.0.0"` |
|
|
728
|
+
| `description` | String | `"A custom theme"` |
|
|
729
|
+
| `colors` | Object at ROOT level | See below |
|
|
730
|
+
|
|
731
|
+
#### Colors Object - MUST be at ROOT level with ALL 8 keys:
|
|
732
|
+
```json
|
|
733
|
+
{
|
|
734
|
+
"colors": {
|
|
735
|
+
"primary": "#4F46E5",
|
|
736
|
+
"secondary": "#10B981",
|
|
737
|
+
"accent": "#F59E0B",
|
|
738
|
+
"background": "#FFFFFF",
|
|
739
|
+
"surface": "#F9FAFB",
|
|
740
|
+
"text": "#1F2937",
|
|
741
|
+
"muted": "#6B7280",
|
|
742
|
+
"border": "#E5E7EB"
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
#### ❌ DO NOT use these patterns:
|
|
748
|
+
- `themeSettings.colors` - WRONG, use `colors` at root
|
|
749
|
+
- `{ "primary": { "default": "#..." } }` - WRONG, use simple hex strings
|
|
750
|
+
- `entryPoint`, `screenshot`, `supports` array - NOT USED
|
|
751
|
+
|
|
752
|
+
#### Complete theme.json Example:
|
|
753
|
+
```json
|
|
754
|
+
{
|
|
755
|
+
"name": "my-theme",
|
|
756
|
+
"displayName": "My Theme",
|
|
757
|
+
"slug": "my-theme",
|
|
758
|
+
"version": "1.0.0",
|
|
759
|
+
"description": "A custom theme",
|
|
760
|
+
"author": "Your Name",
|
|
761
|
+
"colors": {
|
|
762
|
+
"primary": "#4F46E5",
|
|
763
|
+
"secondary": "#10B981",
|
|
764
|
+
"accent": "#F59E0B",
|
|
765
|
+
"background": "#FFFFFF",
|
|
766
|
+
"surface": "#F9FAFB",
|
|
767
|
+
"text": "#1F2937",
|
|
768
|
+
"muted": "#6B7280",
|
|
769
|
+
"border": "#E5E7EB"
|
|
770
|
+
},
|
|
771
|
+
"typography": {
|
|
772
|
+
"headingFont": "Inter, sans-serif",
|
|
773
|
+
"bodyFont": "Inter, sans-serif",
|
|
774
|
+
"baseFontSize": "16px"
|
|
775
|
+
},
|
|
776
|
+
"features": {
|
|
777
|
+
"componentOverrides": true
|
|
778
|
+
},
|
|
779
|
+
"stylesheets": ["styles/theme.css"]
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Step 3: Create components/index.js
|
|
784
|
+
```javascript
|
|
785
|
+
export { default as Header } from './layout/Header';
|
|
786
|
+
// Add more exports as needed
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### Step 4: Create Header.jsx (WITH COMPATIBILITY LAYER)
|
|
790
|
+
|
|
791
|
+
> **⚠️ CRITICAL:** Theme components CANNOT import npm packages or path aliases.
|
|
792
|
+
> This is the #1 cause of production build failures.
|
|
793
|
+
|
|
794
|
+
```javascript
|
|
795
|
+
import React, { useState, useEffect } from 'react'; // ✅ React is aliased
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* THEME COMPATIBILITY LAYER - Required for ALL theme components
|
|
799
|
+
*
|
|
800
|
+
* Theme files live OUTSIDE client workspace, so Vite/Rollup cannot resolve:
|
|
801
|
+
* - npm packages (react-router-dom, react-redux, axios)
|
|
802
|
+
* - path aliases (@/store, @/context)
|
|
803
|
+
*/
|
|
804
|
+
|
|
805
|
+
// ❌ FORBIDDEN - These will break production builds:
|
|
806
|
+
// import { Link } from 'react-router-dom';
|
|
807
|
+
// import { useSelector } from 'react-redux';
|
|
808
|
+
// import axios from 'axios';
|
|
809
|
+
// import { useTheme } from '@/context/ThemeContext';
|
|
810
|
+
|
|
811
|
+
// ✅ Local Link component
|
|
812
|
+
const Link = ({ to, children, className, style, onClick }) => (
|
|
813
|
+
<a href={to} className={className} style={style} onClick={onClick}>{children}</a>
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
// ✅ Navigation hooks using browser APIs
|
|
817
|
+
const useNavigate = () => (path) => { window.location.href = path; };
|
|
818
|
+
const useLocation = () => ({ pathname: window.location.pathname });
|
|
819
|
+
|
|
820
|
+
// ✅ Auth from window global (set by main app)
|
|
821
|
+
const useAuth = () => {
|
|
822
|
+
const [auth, setAuth] = useState({ isAuthenticated: false, user: null });
|
|
823
|
+
useEffect(() => {
|
|
824
|
+
if (window.__LMS_AUTH__) {
|
|
825
|
+
setAuth(window.__LMS_AUTH__);
|
|
826
|
+
} else {
|
|
827
|
+
const token = localStorage.getItem('token');
|
|
828
|
+
const user = localStorage.getItem('user');
|
|
829
|
+
setAuth({ isAuthenticated: !!token, user: user ? JSON.parse(user) : null });
|
|
830
|
+
}
|
|
831
|
+
const handler = () => { /* re-check auth */ };
|
|
832
|
+
window.addEventListener('auth-change', handler);
|
|
833
|
+
return () => window.removeEventListener('auth-change', handler);
|
|
834
|
+
}, []);
|
|
835
|
+
return auth;
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
// ✅ Theme settings from window global
|
|
839
|
+
const useThemeSettings = () => {
|
|
840
|
+
const [settings, setSettings] = useState({});
|
|
841
|
+
useEffect(() => {
|
|
842
|
+
if (window.__LMS_THEME_SETTINGS__) setSettings(window.__LMS_THEME_SETTINGS__);
|
|
843
|
+
}, []);
|
|
844
|
+
return { settings };
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
// ✅ Logout using fetch (not axios + redux dispatch)
|
|
848
|
+
const performLogout = async () => {
|
|
849
|
+
try { await fetch('/api/auth/logout', { method: 'POST' }); } catch(e) {}
|
|
850
|
+
localStorage.removeItem('token');
|
|
851
|
+
localStorage.removeItem('user');
|
|
852
|
+
window.location.href = '/';
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
// Now the actual component:
|
|
856
|
+
const Header = () => {
|
|
857
|
+
const { isAuthenticated, user } = useAuth();
|
|
858
|
+
const { settings } = useThemeSettings();
|
|
859
|
+
const [menuItems, setMenuItems] = useState([]);
|
|
860
|
+
|
|
861
|
+
// ✅ Use fetch() for API calls, not axios
|
|
862
|
+
useEffect(() => {
|
|
863
|
+
fetch('/api/menus?location=header')
|
|
864
|
+
.then(r => r.json())
|
|
865
|
+
.then(d => setMenuItems(d.data?.[0]?.items || []));
|
|
866
|
+
}, []);
|
|
867
|
+
|
|
868
|
+
return (
|
|
869
|
+
<header className="your-custom-styles">
|
|
870
|
+
<Link to="/">Home</Link>
|
|
871
|
+
{isAuthenticated ? (
|
|
872
|
+
<button onClick={performLogout}>Logout</button>
|
|
873
|
+
) : (
|
|
874
|
+
<Link to="/login">Login</Link>
|
|
875
|
+
)}
|
|
876
|
+
</header>
|
|
877
|
+
);
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
export default Header;
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
**Reference:** See `themes/celestial/components/layout/Header.jsx` for complete implementation.
|
|
884
|
+
|
|
885
|
+
### Step 5: Test
|
|
886
|
+
```javascript
|
|
887
|
+
localStorage.setItem('activeTheme', 'my-theme');
|
|
888
|
+
location.reload();
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
---
|
|
892
|
+
|
|
893
|
+
## 🔗 Related Files in This Project
|
|
894
|
+
|
|
895
|
+
- [client/src/services/ThemeManager.js](../../client/src/services/ThemeManager.js)
|
|
896
|
+
- [client/src/contexts/ThemeContext.jsx](../../client/src/contexts/ThemeContext.jsx)
|
|
897
|
+
- [client/src/layouts/MainLayout.jsx](../../client/src/layouts/MainLayout.jsx)
|
|
898
|
+
- [client/vite.config.js](../../client/vite.config.js)
|
|
899
|
+
- [themes/celestial/](../../themes/celestial/)
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## 📚 Key Concepts
|
|
904
|
+
|
|
905
|
+
| Concept | Description |
|
|
906
|
+
|---------|-------------|
|
|
907
|
+
| **Component Override** | Theme provides replacement for core component |
|
|
908
|
+
| **Fallback Pattern** | `getComponent('X') \|\| DefaultX` |
|
|
909
|
+
| **Lazy Loading** | Theme components loaded via `import.meta.glob` |
|
|
910
|
+
| **Suspense Boundary** | React.Suspense wraps lazy components |
|
|
911
|
+
| **Alias Resolution** | `@themes` → `../themes` in Vite config |
|
|
912
|
+
|
|
913
|
+
---
|
|
914
|
+
|
|
915
|
+
## 🔌 Puck Editor Integration
|
|
916
|
+
|
|
917
|
+
Theme-specific Puck components allow the page builder to use themed blocks.
|
|
918
|
+
|
|
919
|
+
### Puck Component Structure (themes/[theme]/puck/index.jsx)
|
|
920
|
+
|
|
921
|
+
```jsx
|
|
922
|
+
/**
|
|
923
|
+
* Each Puck component export is an object with:
|
|
924
|
+
* - label: Display name in Puck sidebar
|
|
925
|
+
* - fields: Form fields for the editor
|
|
926
|
+
* - defaultProps: Initial values
|
|
927
|
+
* - render: React component to render
|
|
928
|
+
*/
|
|
929
|
+
export const CelestialHero = {
|
|
930
|
+
label: 'Celestial Hero',
|
|
931
|
+
|
|
932
|
+
// Field definitions for the Puck editor sidebar
|
|
933
|
+
fields: {
|
|
934
|
+
variant: {
|
|
935
|
+
type: 'select',
|
|
936
|
+
label: 'Style Variant',
|
|
937
|
+
options: [
|
|
938
|
+
{ label: 'Full Width with Overlay', value: 'fullWidth' },
|
|
939
|
+
{ label: 'Split Layout', value: 'split' },
|
|
940
|
+
{ label: 'Minimal Centered', value: 'minimal' }
|
|
941
|
+
]
|
|
942
|
+
},
|
|
943
|
+
title: {
|
|
944
|
+
type: 'text',
|
|
945
|
+
label: 'Title'
|
|
946
|
+
},
|
|
947
|
+
subtitle: {
|
|
948
|
+
type: 'textarea',
|
|
949
|
+
label: 'Subtitle'
|
|
950
|
+
},
|
|
951
|
+
backgroundImage: {
|
|
952
|
+
type: 'text',
|
|
953
|
+
label: 'Background Image URL'
|
|
954
|
+
},
|
|
955
|
+
primaryButtonText: {
|
|
956
|
+
type: 'text',
|
|
957
|
+
label: 'Primary Button Text'
|
|
958
|
+
},
|
|
959
|
+
primaryButtonLink: {
|
|
960
|
+
type: 'text',
|
|
961
|
+
label: 'Primary Button Link'
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
|
|
965
|
+
// Default values when component is first added
|
|
966
|
+
defaultProps: {
|
|
967
|
+
variant: 'fullWidth',
|
|
968
|
+
title: 'Welcome to Our Ministry',
|
|
969
|
+
subtitle: 'Discover transformative teaching',
|
|
970
|
+
backgroundImage: '',
|
|
971
|
+
primaryButtonText: 'Get Started',
|
|
972
|
+
primaryButtonLink: '/register'
|
|
973
|
+
},
|
|
974
|
+
|
|
975
|
+
// The actual React component
|
|
976
|
+
render: ({ variant, title, subtitle, backgroundImage, primaryButtonText, primaryButtonLink }) => {
|
|
977
|
+
return (
|
|
978
|
+
<section className="min-h-[70vh] flex items-center justify-center">
|
|
979
|
+
<h1>{title}</h1>
|
|
980
|
+
<p>{subtitle}</p>
|
|
981
|
+
<a href={primaryButtonLink}>{primaryButtonText}</a>
|
|
982
|
+
</section>
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
// Export more components...
|
|
988
|
+
export const CelestialCard = { /* ... */ };
|
|
989
|
+
export const CelestialButton = { /* ... */ };
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
### Accessing Puck Components in ThemeContext
|
|
993
|
+
|
|
994
|
+
```javascript
|
|
995
|
+
// ThemeContext provides getPuckComponents()
|
|
996
|
+
const { getPuckComponents } = useTheme();
|
|
997
|
+
|
|
998
|
+
// Returns merged object of all theme Puck components
|
|
999
|
+
const themePuckComponents = getPuckComponents();
|
|
1000
|
+
|
|
1001
|
+
// Use in Puck editor config
|
|
1002
|
+
const puckConfig = {
|
|
1003
|
+
components: {
|
|
1004
|
+
...defaultComponents,
|
|
1005
|
+
...themePuckComponents // Theme components override/extend defaults
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
### Puck Field Types Reference
|
|
1011
|
+
|
|
1012
|
+
| Type | Description | Options |
|
|
1013
|
+
|------|-------------|---------|
|
|
1014
|
+
| `text` | Single line input | - |
|
|
1015
|
+
| `textarea` | Multi-line input | - |
|
|
1016
|
+
| `number` | Numeric input | `min`, `max`, `step` |
|
|
1017
|
+
| `select` | Dropdown | `options: [{ label, value }]` |
|
|
1018
|
+
| `radio` | Radio buttons | `options: [{ label, value }]` |
|
|
1019
|
+
| `external` | External data | `fetchList`, `mapRow` |
|
|
1020
|
+
| `custom` | Custom component | `render` function |
|
|
1021
|
+
|
|
1022
|
+
---
|
|
1023
|
+
|
|
1024
|
+
## 🎨 Theme CSS Loading System
|
|
1025
|
+
|
|
1026
|
+
CSS stylesheets are dynamically injected into the document head.
|
|
1027
|
+
|
|
1028
|
+
### How It Works (ThemeContext.jsx)
|
|
1029
|
+
|
|
1030
|
+
```javascript
|
|
1031
|
+
// Track injected stylesheets for cleanup
|
|
1032
|
+
let injectedStylesheets = [];
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Inject theme CSS stylesheet into document head
|
|
1036
|
+
*/
|
|
1037
|
+
const injectThemeStylesheet = (themeSlug, cssPath) => {
|
|
1038
|
+
const linkId = `theme-css-${themeSlug}-${cssPath.replace(/[^a-z0-9]/gi, '-')}`;
|
|
1039
|
+
|
|
1040
|
+
// Prevent duplicate injection
|
|
1041
|
+
if (document.getElementById(linkId)) return;
|
|
1042
|
+
|
|
1043
|
+
const link = document.createElement('link');
|
|
1044
|
+
link.id = linkId;
|
|
1045
|
+
link.rel = 'stylesheet';
|
|
1046
|
+
link.type = 'text/css';
|
|
1047
|
+
link.href = `/themes/${themeSlug}/${cssPath}`;
|
|
1048
|
+
link.setAttribute('data-theme', themeSlug);
|
|
1049
|
+
|
|
1050
|
+
document.head.appendChild(link);
|
|
1051
|
+
injectedStylesheets.push(linkId);
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Remove theme stylesheets on theme change
|
|
1056
|
+
*/
|
|
1057
|
+
const removeThemeStylesheets = (themeSlug = null) => {
|
|
1058
|
+
const selector = themeSlug
|
|
1059
|
+
? `link[data-theme="${themeSlug}"]`
|
|
1060
|
+
: 'link[data-theme]';
|
|
1061
|
+
|
|
1062
|
+
document.querySelectorAll(selector).forEach(link => link.remove());
|
|
1063
|
+
};
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Load CSS from theme settings or default path
|
|
1067
|
+
*/
|
|
1068
|
+
const loadThemeCSS = (themeSlug, themeSettings) => {
|
|
1069
|
+
// Clean up previous theme CSS
|
|
1070
|
+
removeThemeStylesheets();
|
|
1071
|
+
|
|
1072
|
+
if (!themeSlug || themeSlug === 'default') return;
|
|
1073
|
+
|
|
1074
|
+
// Check for explicit stylesheets in theme.json settings
|
|
1075
|
+
if (themeSettings?.stylesheets) {
|
|
1076
|
+
const sheets = Array.isArray(themeSettings.stylesheets)
|
|
1077
|
+
? themeSettings.stylesheets
|
|
1078
|
+
: [themeSettings.stylesheets];
|
|
1079
|
+
|
|
1080
|
+
sheets.forEach(cssPath => injectThemeStylesheet(themeSlug, cssPath));
|
|
1081
|
+
} else {
|
|
1082
|
+
// Default: look for styles/theme.css
|
|
1083
|
+
injectThemeStylesheet(themeSlug, 'styles/theme.css');
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
### Theme.json Stylesheet Configuration
|
|
1089
|
+
|
|
1090
|
+
```json
|
|
1091
|
+
{
|
|
1092
|
+
"name": "Celestial",
|
|
1093
|
+
"slug": "celestial",
|
|
1094
|
+
"settings": {
|
|
1095
|
+
"stylesheets": [
|
|
1096
|
+
"styles/theme.css",
|
|
1097
|
+
"styles/animations.css"
|
|
1098
|
+
]
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
### CSS Variables Applied by ThemeManager
|
|
1104
|
+
|
|
1105
|
+
```javascript
|
|
1106
|
+
// ThemeManager.applyCSSVariables() sets these on :root
|
|
1107
|
+
const cssVariables = {
|
|
1108
|
+
// Colors
|
|
1109
|
+
'--color-primary': '#1E1B4B',
|
|
1110
|
+
'--color-primary-50': '#f5f3ff', // Auto-generated lighter
|
|
1111
|
+
'--color-primary-900': '#1e1b4b', // Auto-generated darker
|
|
1112
|
+
'--color-secondary': '#D4AF37',
|
|
1113
|
+
'--color-background': '#FDF8F0',
|
|
1114
|
+
'--color-surface': '#FFFEF5',
|
|
1115
|
+
'--color-text': '#1F1F2E',
|
|
1116
|
+
'--color-muted': '#64748B',
|
|
1117
|
+
'--color-border': '#E2D5BB',
|
|
1118
|
+
|
|
1119
|
+
// Typography
|
|
1120
|
+
'--font-heading': 'Playfair Display, serif',
|
|
1121
|
+
'--font-body': 'Inter, sans-serif',
|
|
1122
|
+
'--font-size-base': '16px',
|
|
1123
|
+
|
|
1124
|
+
// Layout
|
|
1125
|
+
'--max-width': '1280px',
|
|
1126
|
+
'--header-height': '80px',
|
|
1127
|
+
|
|
1128
|
+
// Components
|
|
1129
|
+
'--radius-card': '12px',
|
|
1130
|
+
'--radius-button': '8px'
|
|
1131
|
+
};
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
## 💾 Server-Side Theme Storage
|
|
1137
|
+
|
|
1138
|
+
### Database Schema (themes table)
|
|
1139
|
+
|
|
1140
|
+
```sql
|
|
1141
|
+
CREATE TABLE themes (
|
|
1142
|
+
id SERIAL PRIMARY KEY,
|
|
1143
|
+
slug VARCHAR(100) UNIQUE NOT NULL,
|
|
1144
|
+
name VARCHAR(255) NOT NULL,
|
|
1145
|
+
description TEXT,
|
|
1146
|
+
version VARCHAR(20),
|
|
1147
|
+
author VARCHAR(255),
|
|
1148
|
+
is_active BOOLEAN DEFAULT false, -- Only one theme active at a time
|
|
1149
|
+
settings JSONB DEFAULT '{}',
|
|
1150
|
+
customizations JSONB DEFAULT '{}',
|
|
1151
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
1152
|
+
updated_at TIMESTAMP DEFAULT NOW()
|
|
1153
|
+
);
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
### API Endpoints
|
|
1157
|
+
|
|
1158
|
+
```javascript
|
|
1159
|
+
// Get active theme (public)
|
|
1160
|
+
GET /api/themes/active
|
|
1161
|
+
// Response: { success: true, data: { slug, name, settings, customizations } }
|
|
1162
|
+
|
|
1163
|
+
// List all themes (admin)
|
|
1164
|
+
GET /api/themes
|
|
1165
|
+
|
|
1166
|
+
// Activate a theme (admin)
|
|
1167
|
+
PUT /api/themes/:slug/activate
|
|
1168
|
+
|
|
1169
|
+
// Update theme customizations (admin)
|
|
1170
|
+
PUT /api/themes/:slug/customizations
|
|
1171
|
+
// Body: { colors: { primary: '#...' }, typography: { ... } }
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
### Frontend Theme Loading
|
|
1175
|
+
|
|
1176
|
+
```javascript
|
|
1177
|
+
// ThemeContext.jsx - loadActiveTheme()
|
|
1178
|
+
const loadActiveTheme = async () => {
|
|
1179
|
+
try {
|
|
1180
|
+
const response = await api.get('/themes/active');
|
|
1181
|
+
if (response.data.success) {
|
|
1182
|
+
const themeData = response.data.data;
|
|
1183
|
+
|
|
1184
|
+
// Load into ThemeManager
|
|
1185
|
+
await themeManager.loadTheme(themeData.slug, themeData);
|
|
1186
|
+
|
|
1187
|
+
// Load CSS stylesheets
|
|
1188
|
+
loadThemeCSS(themeData.slug, themeData.settings);
|
|
1189
|
+
|
|
1190
|
+
setTheme(themeData);
|
|
1191
|
+
}
|
|
1192
|
+
} catch (error) {
|
|
1193
|
+
console.error('Failed to load theme:', error);
|
|
1194
|
+
// Fall back to default theme
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
### Per-User Theme Preference (Partial Implementation)
|
|
1200
|
+
|
|
1201
|
+
```javascript
|
|
1202
|
+
// User preferences stored in profiles.settings JSONB
|
|
1203
|
+
// Query example:
|
|
1204
|
+
await db.queryJSON('profiles', 'settings', '$.theme', 'dark');
|
|
1205
|
+
|
|
1206
|
+
// To implement user preference override:
|
|
1207
|
+
// 1. Check user.settings.theme on login
|
|
1208
|
+
// 2. If set, use that instead of site-wide active theme
|
|
1209
|
+
// 3. Store preference: PUT /api/users/preferences { theme: 'celestial' }
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
---
|
|
1213
|
+
|
|
1214
|
+
## 🔥 Hot Module Replacement (HMR) Gotchas
|
|
1215
|
+
|
|
1216
|
+
### What Works
|
|
1217
|
+
|
|
1218
|
+
| Change Type | HMR Behavior |
|
|
1219
|
+
|-------------|--------------|
|
|
1220
|
+
| Theme component JSX | ✅ Hot reloads |
|
|
1221
|
+
| Theme component styles (inline/Tailwind) | ✅ Hot reloads |
|
|
1222
|
+
| Theme CSS variables in JS | ✅ Hot reloads |
|
|
1223
|
+
| Export names in index.js | ⚠️ May need manual refresh |
|
|
1224
|
+
|
|
1225
|
+
### What Requires Manual Refresh
|
|
1226
|
+
|
|
1227
|
+
| Change Type | Workaround |
|
|
1228
|
+
|-------------|------------|
|
|
1229
|
+
| Theme CSS files (theme.css) | Injected via `<link>`, not Vite pipeline |
|
|
1230
|
+
| New theme folder added | `import.meta.glob` is static, restart Vite |
|
|
1231
|
+
| theme.json changes | Reload page to refetch from API |
|
|
1232
|
+
| Puck field definitions | Restart Puck editor page |
|
|
1233
|
+
|
|
1234
|
+
### Development Tips
|
|
1235
|
+
|
|
1236
|
+
```bash
|
|
1237
|
+
# If HMR seems stuck, try:
|
|
1238
|
+
# 1. Save the file again (triggers re-evaluation)
|
|
1239
|
+
# 2. Clear browser cache and hard reload (Ctrl+Shift+R)
|
|
1240
|
+
# 3. Restart Vite dev server
|
|
1241
|
+
|
|
1242
|
+
# Watch for this console message indicating theme loaded:
|
|
1243
|
+
# [ThemeManager] Loaded 3 component overrides
|
|
1244
|
+
# [ThemeContext] Injected stylesheet: /themes/celestial/styles/theme.css
|
|
1245
|
+
```
|
|
1246
|
+
|
|
1247
|
+
### Vite HMR Debug
|
|
1248
|
+
|
|
1249
|
+
```javascript
|
|
1250
|
+
// Add to component for HMR debugging
|
|
1251
|
+
if (import.meta.hot) {
|
|
1252
|
+
import.meta.hot.accept(() => {
|
|
1253
|
+
console.log('Theme component hot updated');
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
---
|
|
1259
|
+
|
|
1260
|
+
## 📦 Production Build Considerations
|
|
1261
|
+
|
|
1262
|
+
### Vite Build Output
|
|
1263
|
+
|
|
1264
|
+
```bash
|
|
1265
|
+
npm run build
|
|
1266
|
+
# Outputs to client/dist/
|
|
1267
|
+
# Theme JS components are bundled via import.meta.glob
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
### Critical: Serve Themes Folder
|
|
1271
|
+
|
|
1272
|
+
Theme CSS files are NOT bundled - they're loaded at runtime. Your server must serve them:
|
|
1273
|
+
|
|
1274
|
+
```javascript
|
|
1275
|
+
// server/app.js - Add this line
|
|
1276
|
+
const path = require('path');
|
|
1277
|
+
|
|
1278
|
+
// Serve theme static files (CSS, images, fonts)
|
|
1279
|
+
app.use('/themes', express.static(path.join(__dirname, '../themes')));
|
|
1280
|
+
|
|
1281
|
+
// Or with options:
|
|
1282
|
+
app.use('/themes', express.static(path.join(__dirname, '../themes'), {
|
|
1283
|
+
maxAge: '1d', // Cache for 1 day
|
|
1284
|
+
etag: true,
|
|
1285
|
+
lastModified: true
|
|
1286
|
+
}));
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
### Nginx Configuration (if using)
|
|
1290
|
+
|
|
1291
|
+
```nginx
|
|
1292
|
+
# Serve themes folder
|
|
1293
|
+
location /themes/ {
|
|
1294
|
+
alias /var/www/app/themes/;
|
|
1295
|
+
expires 1d;
|
|
1296
|
+
add_header Cache-Control "public, immutable";
|
|
1297
|
+
}
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
### Docker Considerations
|
|
1301
|
+
|
|
1302
|
+
```dockerfile
|
|
1303
|
+
# Ensure themes folder is copied
|
|
1304
|
+
COPY themes/ /app/themes/
|
|
1305
|
+
|
|
1306
|
+
# Or mount as volume in docker-compose.yml
|
|
1307
|
+
volumes:
|
|
1308
|
+
- ./themes:/app/themes:ro
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
### Verify Build Includes Theme Components
|
|
1312
|
+
|
|
1313
|
+
```bash
|
|
1314
|
+
# After build, check that theme components are in the bundle
|
|
1315
|
+
grep -r "CelestialHero" client/dist/assets/*.js
|
|
1316
|
+
# Should find minified references to theme components
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
---
|
|
1320
|
+
|
|
1321
|
+
## 🌙 Dark Mode Integration
|
|
1322
|
+
|
|
1323
|
+
### Current Implementation: Separate Themes
|
|
1324
|
+
|
|
1325
|
+
Dark mode is currently a separate theme (`dark-mode`) rather than a toggle:
|
|
1326
|
+
|
|
1327
|
+
```json
|
|
1328
|
+
// themes/dark-mode/theme.json
|
|
1329
|
+
{
|
|
1330
|
+
"name": "Dark Mode",
|
|
1331
|
+
"slug": "dark-mode",
|
|
1332
|
+
"settings": {
|
|
1333
|
+
"colors": {
|
|
1334
|
+
"background": "#1a1a2e",
|
|
1335
|
+
"surface": "#16213e",
|
|
1336
|
+
"text": "#eaeaea",
|
|
1337
|
+
"primary": "#4a9eff"
|
|
1338
|
+
},
|
|
1339
|
+
"features": {
|
|
1340
|
+
"darkMode": true
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
### Per-Theme Dark Mode Support
|
|
1347
|
+
|
|
1348
|
+
Some themes support internal dark mode via settings:
|
|
1349
|
+
|
|
1350
|
+
```json
|
|
1351
|
+
// themes/classic/theme.json
|
|
1352
|
+
{
|
|
1353
|
+
"settings": {
|
|
1354
|
+
"features": {
|
|
1355
|
+
"darkMode": {
|
|
1356
|
+
"enabled": true,
|
|
1357
|
+
"colors": {
|
|
1358
|
+
"background": "#1f2937",
|
|
1359
|
+
"text": "#f9fafb"
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
```
|
|
1366
|
+
|
|
1367
|
+
### Implementing Universal Dark Mode Toggle
|
|
1368
|
+
|
|
1369
|
+
```javascript
|
|
1370
|
+
// Option 1: CSS class toggle (recommended)
|
|
1371
|
+
const toggleDarkMode = () => {
|
|
1372
|
+
document.documentElement.classList.toggle('dark');
|
|
1373
|
+
localStorage.setItem('darkMode', document.documentElement.classList.contains('dark'));
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
// In theme CSS:
|
|
1377
|
+
:root {
|
|
1378
|
+
--color-background: #ffffff;
|
|
1379
|
+
--color-text: #1f1f2e;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
:root.dark {
|
|
1383
|
+
--color-background: #1a1a2e;
|
|
1384
|
+
--color-text: #eaeaea;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// Option 2: Theme variant switching
|
|
1388
|
+
const setThemeVariant = (variant) => {
|
|
1389
|
+
// Load dark variant of current theme
|
|
1390
|
+
await themeManager.loadTheme(`${currentTheme}-dark`, themeData);
|
|
1391
|
+
};
|
|
1392
|
+
```
|
|
1393
|
+
|
|
1394
|
+
### Respecting System Preference
|
|
1395
|
+
|
|
1396
|
+
```javascript
|
|
1397
|
+
// Check system preference on load
|
|
1398
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
1399
|
+
|
|
1400
|
+
// Listen for changes
|
|
1401
|
+
window.matchMedia('(prefers-color-scheme: dark)')
|
|
1402
|
+
.addEventListener('change', (e) => {
|
|
1403
|
+
if (e.matches) {
|
|
1404
|
+
enableDarkMode();
|
|
1405
|
+
} else {
|
|
1406
|
+
disableDarkMode();
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
---
|
|
1412
|
+
|
|
1413
|
+
## 🛡️ Error Boundaries for Theme Components
|
|
1414
|
+
|
|
1415
|
+
### Problem
|
|
1416
|
+
|
|
1417
|
+
If a theme component throws an error, it can crash the entire page.
|
|
1418
|
+
|
|
1419
|
+
### Solution: Wrap Theme Components
|
|
1420
|
+
|
|
1421
|
+
```jsx
|
|
1422
|
+
// client/src/layouts/MainLayout.jsx
|
|
1423
|
+
import ErrorBoundary from '../components/common/ErrorBoundary';
|
|
1424
|
+
|
|
1425
|
+
const MainLayoutInner = () => {
|
|
1426
|
+
const { getComponent } = useTheme();
|
|
1427
|
+
|
|
1428
|
+
const Header = getComponent('Header', DefaultHeader);
|
|
1429
|
+
const Footer = getComponent('Footer', DefaultFooter);
|
|
1430
|
+
|
|
1431
|
+
return (
|
|
1432
|
+
<div className="min-h-screen flex flex-col">
|
|
1433
|
+
{/* Wrap header with fallback */}
|
|
1434
|
+
<ErrorBoundary
|
|
1435
|
+
fallback={<DefaultHeader />}
|
|
1436
|
+
onError={(error) => console.error('Theme Header crashed:', error)}
|
|
1437
|
+
>
|
|
1438
|
+
<Suspense fallback={<ComponentLoader type="header" />}>
|
|
1439
|
+
<Header />
|
|
1440
|
+
</Suspense>
|
|
1441
|
+
</ErrorBoundary>
|
|
1442
|
+
|
|
1443
|
+
<main className="flex-1">
|
|
1444
|
+
{children}
|
|
1445
|
+
</main>
|
|
1446
|
+
|
|
1447
|
+
{/* Wrap footer with fallback */}
|
|
1448
|
+
<ErrorBoundary
|
|
1449
|
+
fallback={<DefaultFooter />}
|
|
1450
|
+
onError={(error) => console.error('Theme Footer crashed:', error)}
|
|
1451
|
+
>
|
|
1452
|
+
<Suspense fallback={<ComponentLoader type="footer" />}>
|
|
1453
|
+
<Footer />
|
|
1454
|
+
</Suspense>
|
|
1455
|
+
</ErrorBoundary>
|
|
1456
|
+
</div>
|
|
1457
|
+
);
|
|
1458
|
+
};
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
### Enhanced ErrorBoundary with Reset
|
|
1462
|
+
|
|
1463
|
+
```jsx
|
|
1464
|
+
// components/common/ThemeErrorBoundary.jsx
|
|
1465
|
+
import React from 'react';
|
|
1466
|
+
|
|
1467
|
+
class ThemeErrorBoundary extends React.Component {
|
|
1468
|
+
state = { hasError: false, error: null };
|
|
1469
|
+
|
|
1470
|
+
static getDerivedStateFromError(error) {
|
|
1471
|
+
return { hasError: true, error };
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
componentDidCatch(error, errorInfo) {
|
|
1475
|
+
console.error(`[ThemeErrorBoundary] ${this.props.componentName} failed:`, error);
|
|
1476
|
+
|
|
1477
|
+
// Optional: Report to error tracking service
|
|
1478
|
+
// errorReporter.captureException(error, { componentName: this.props.componentName });
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
render() {
|
|
1482
|
+
if (this.state.hasError) {
|
|
1483
|
+
// Render fallback component
|
|
1484
|
+
const Fallback = this.props.fallback;
|
|
1485
|
+
return Fallback ? <Fallback /> : (
|
|
1486
|
+
<div className="p-4 bg-red-50 text-red-700 text-center">
|
|
1487
|
+
Failed to load {this.props.componentName}. Using default.
|
|
1488
|
+
</div>
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
return this.props.children;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
export default ThemeErrorBoundary;
|
|
1497
|
+
```
|
|
1498
|
+
|
|
1499
|
+
### Usage Pattern
|
|
1500
|
+
|
|
1501
|
+
```jsx
|
|
1502
|
+
<ThemeErrorBoundary componentName="Header" fallback={DefaultHeader}>
|
|
1503
|
+
<ThemedHeader />
|
|
1504
|
+
</ThemeErrorBoundary>
|
|
1505
|
+
```
|
|
1506
|
+
|
|
1507
|
+
---
|
|
1508
|
+
|
|
1509
|
+
## 📊 Implementation Status Summary
|
|
1510
|
+
|
|
1511
|
+
| Feature | Status | Location |
|
|
1512
|
+
|---------|--------|----------|
|
|
1513
|
+
| Component Overrides | ✅ Complete | ThemeManager.js, MainLayout.jsx |
|
|
1514
|
+
| Puck Components | ✅ Complete | ThemeManager.loadPuckComponents() |
|
|
1515
|
+
| CSS Loading | ✅ Complete | ThemeContext.jsx |
|
|
1516
|
+
| CSS Variables | ✅ Complete | ThemeManager.applyCSSVariables() |
|
|
1517
|
+
| API Persistence | ✅ Complete | /api/themes/active |
|
|
1518
|
+
| User Preferences | ⚠️ Partial | DB ready, needs frontend wiring |
|
|
1519
|
+
| HMR Support | ⚠️ Works with gotchas | See notes above |
|
|
1520
|
+
| Production Build | ⚠️ Needs static serving | Configure Express/Nginx |
|
|
1521
|
+
| Dark Mode | ⚠️ Separate themes only | No universal toggle |
|
|
1522
|
+
| Error Boundaries | ❌ Not implemented | Should wrap theme components |
|
|
1523
|
+
|
|
1524
|
+
---
|
|
1525
|
+
|
|
1526
|
+
*Last Updated: January 17, 2026*
|