@julianoczkowski/create-trimble-app 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -0
- package/bin/create-trimble-app.js +9 -0
- package/package.json +67 -0
- package/src/cli.js +134 -0
- package/src/frameworks.js +28 -0
- package/src/scaffold.js +209 -0
- package/src/utils/file.js +47 -0
- package/src/utils/git.js +140 -0
- package/src/utils/install.js +25 -0
- package/src/utils/logger.js +124 -0
- package/templates/angular/.cursor/commands/remove-dev-content.md +394 -0
- package/templates/angular/.cursor/mcp.json +13 -0
- package/templates/angular/.cursor/rules/modus-angular-20.mdc +82 -0
- package/templates/angular/.cursor/rules/modus-angular-accordion-state-management-short.mdc +45 -0
- package/templates/angular/.cursor/rules/modus-angular-accordion-state-management.mdc +322 -0
- package/templates/angular/.cursor/rules/modus-angular-best-practices.mdc +472 -0
- package/templates/angular/.cursor/rules/modus-angular-border-usage-short.mdc +48 -0
- package/templates/angular/.cursor/rules/modus-angular-border-usage.mdc +286 -0
- package/templates/angular/.cursor/rules/modus-angular-button-group-usage-short.mdc +47 -0
- package/templates/angular/.cursor/rules/modus-angular-button-group-usage.mdc +263 -0
- package/templates/angular/.cursor/rules/modus-angular-checkbox-value-inversion-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-checkbox-value-inversion.mdc +92 -0
- package/templates/angular/.cursor/rules/modus-angular-chrome-devtools-testing-short.mdc +34 -0
- package/templates/angular/.cursor/rules/modus-angular-chrome-devtools-testing.mdc +185 -0
- package/templates/angular/.cursor/rules/modus-angular-color-usage-short.mdc +56 -0
- package/templates/angular/.cursor/rules/modus-angular-color-usage.mdc +208 -0
- package/templates/angular/.cursor/rules/modus-angular-components-reference.mdc +114 -0
- package/templates/angular/.cursor/rules/modus-angular-design-system.mdc +273 -0
- package/templates/angular/.cursor/rules/modus-angular-development-workflow-short.mdc +43 -0
- package/templates/angular/.cursor/rules/modus-angular-development-workflow.mdc +145 -0
- package/templates/angular/.cursor/rules/modus-angular-essentials.mdc +272 -0
- package/templates/angular/.cursor/rules/modus-angular-forms-validation-short.mdc +56 -0
- package/templates/angular/.cursor/rules/modus-angular-forms-validation.mdc +124 -0
- package/templates/angular/.cursor/rules/modus-angular-icon-names.mdc +70 -0
- package/templates/angular/.cursor/rules/modus-angular-icons-short.mdc +40 -0
- package/templates/angular/.cursor/rules/modus-angular-icons.mdc +137 -0
- package/templates/angular/.cursor/rules/modus-angular-implementation-guides-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-implementation-guides.mdc +301 -0
- package/templates/angular/.cursor/rules/modus-angular-integration-short.mdc +60 -0
- package/templates/angular/.cursor/rules/modus-angular-integration.mdc +1096 -0
- package/templates/angular/.cursor/rules/modus-angular-master.mdc +164 -0
- package/templates/angular/.cursor/rules/modus-angular-modal-usage-short.mdc +51 -0
- package/templates/angular/.cursor/rules/modus-angular-modal-usage.mdc +115 -0
- package/templates/angular/.cursor/rules/modus-angular-navbar-usage-short.mdc +49 -0
- package/templates/angular/.cursor/rules/modus-angular-navbar-usage.mdc +146 -0
- package/templates/angular/.cursor/rules/modus-angular-no-emojis.mdc +66 -0
- package/templates/angular/.cursor/rules/modus-angular-opacity-utilities-short.mdc +43 -0
- package/templates/angular/.cursor/rules/modus-angular-opacity-utilities.mdc +160 -0
- package/templates/angular/.cursor/rules/modus-angular-select-vs-dropdown-menu-short.mdc +51 -0
- package/templates/angular/.cursor/rules/modus-angular-select-vs-dropdown-menu.mdc +83 -0
- package/templates/angular/.cursor/rules/modus-angular-semantic-html-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-semantic-html.mdc +81 -0
- package/templates/angular/.cursor/rules/modus-angular-side-navigation-usage-short.mdc +50 -0
- package/templates/angular/.cursor/rules/modus-angular-side-navigation-usage.mdc +136 -0
- package/templates/angular/.cursor/rules/modus-angular-table-usage-short.mdc +52 -0
- package/templates/angular/.cursor/rules/modus-angular-table-usage.mdc +151 -0
- package/templates/angular/.cursor/rules/modus-angular-tailwind-usage-short.mdc +44 -0
- package/templates/angular/.cursor/rules/modus-angular-tailwind-usage.mdc +242 -0
- package/templates/angular/.cursor/rules/modus-angular-themes-short.mdc +54 -0
- package/templates/angular/.cursor/rules/modus-angular-themes.mdc +222 -0
- package/templates/angular/.cursor/rules/modus-angular-utility-panel-usage-short.mdc +52 -0
- package/templates/angular/.cursor/rules/modus-angular-utility-panel-usage.mdc +130 -0
- package/templates/angular/.cursor/rules/ux/gestalt-laws-detailed.mdc +514 -0
- package/templates/angular/.cursor/rules/ux/ux-ui-foundations.mdc +235 -0
- package/templates/angular/.cursor/skills/run-lint-checks/SKILL.md +169 -0
- package/templates/angular/.editorconfig +17 -0
- package/templates/angular/.github/dependabot.yml +19 -0
- package/templates/angular/.github/workflows/a11y-check.yml +135 -0
- package/templates/angular/.github/workflows/ci.yml +44 -0
- package/templates/angular/.husky/pre-commit +32 -0
- package/templates/angular/.postcssrc.json +5 -0
- package/templates/angular/.vscode/extensions.json +4 -0
- package/templates/angular/.vscode/launch.json +20 -0
- package/templates/angular/.vscode/tasks.json +42 -0
- package/templates/angular/CLAUDE.md +148 -0
- package/templates/angular/README.md +92 -0
- package/templates/angular/amplify.yml +25 -0
- package/templates/angular/angular.json +106 -0
- package/templates/angular/data/modusIcons.ts +861 -0
- package/templates/angular/package-lock.json +11030 -0
- package/templates/angular/package.json +66 -0
- package/templates/angular/public/angular-icon.svg +12 -0
- package/templates/angular/public/favicon.ico +0 -0
- package/templates/angular/public/modus-icons.css +49 -0
- package/templates/angular/public/vite.svg +1 -0
- package/templates/angular/scripts/README.md +410 -0
- package/templates/angular/scripts/check-border-violations.js +352 -0
- package/templates/angular/scripts/check-icon-names.js +402 -0
- package/templates/angular/scripts/check-inline-styles.js +292 -0
- package/templates/angular/scripts/check-modus-colors.js +282 -0
- package/templates/angular/scripts/check-modus-icons.js +263 -0
- package/templates/angular/scripts/check-opacity-utilities.js +426 -0
- package/templates/angular/scripts/check-semantic-html.js +452 -0
- package/templates/angular/scripts/check-typescript.js +109 -0
- package/templates/angular/src/app/app.config.ts +29 -0
- package/templates/angular/src/app/app.css +0 -0
- package/templates/angular/src/app/app.html +4 -0
- package/templates/angular/src/app/app.routes.ts +351 -0
- package/templates/angular/src/app/app.spec.ts +27 -0
- package/templates/angular/src/app/app.ts +47 -0
- package/templates/angular/src/app/components/README.md +77 -0
- package/templates/angular/src/app/components/index.ts +53 -0
- package/templates/angular/src/app/components/modus-accordion.component.ts +50 -0
- package/templates/angular/src/app/components/modus-alert.component.ts +133 -0
- package/templates/angular/src/app/components/modus-autocomplete.component.ts +262 -0
- package/templates/angular/src/app/components/modus-avatar.component.ts +75 -0
- package/templates/angular/src/app/components/modus-badge.component.ts +84 -0
- package/templates/angular/src/app/components/modus-breadcrumbs.component.ts +65 -0
- package/templates/angular/src/app/components/modus-button-group.component.ts +82 -0
- package/templates/angular/src/app/components/modus-button.component.ts +292 -0
- package/templates/angular/src/app/components/modus-card.component.ts +73 -0
- package/templates/angular/src/app/components/modus-checkbox.component.ts +117 -0
- package/templates/angular/src/app/components/modus-chip.component.ts +97 -0
- package/templates/angular/src/app/components/modus-collapse.component.ts +118 -0
- package/templates/angular/src/app/components/modus-date.component.ts +165 -0
- package/templates/angular/src/app/components/modus-dropdown-menu.component.ts +108 -0
- package/templates/angular/src/app/components/modus-file-dropzone.component.ts +121 -0
- package/templates/angular/src/app/components/modus-handle.component.ts +96 -0
- package/templates/angular/src/app/components/modus-icon.component.ts +81 -0
- package/templates/angular/src/app/components/modus-input-feedback.component.ts +54 -0
- package/templates/angular/src/app/components/modus-input-label.component.ts +62 -0
- package/templates/angular/src/app/components/modus-loader.component.ts +48 -0
- package/templates/angular/src/app/components/modus-logo.component.ts +115 -0
- package/templates/angular/src/app/components/modus-menu-item.component.ts +116 -0
- package/templates/angular/src/app/components/modus-menu.component.ts +58 -0
- package/templates/angular/src/app/components/modus-modal.component.ts +70 -0
- package/templates/angular/src/app/components/modus-navbar.component.ts +303 -0
- package/templates/angular/src/app/components/modus-number-input.component.ts +174 -0
- package/templates/angular/src/app/components/modus-pagination.component.ts +74 -0
- package/templates/angular/src/app/components/modus-panel.component.ts +61 -0
- package/templates/angular/src/app/components/modus-progress.component.ts +62 -0
- package/templates/angular/src/app/components/modus-radio.component.ts +102 -0
- package/templates/angular/src/app/components/modus-rating.component.ts +80 -0
- package/templates/angular/src/app/components/modus-select.component.ts +131 -0
- package/templates/angular/src/app/components/modus-side-navigation.component.ts +90 -0
- package/templates/angular/src/app/components/modus-skeleton.component.ts +54 -0
- package/templates/angular/src/app/components/modus-slider.component.ts +132 -0
- package/templates/angular/src/app/components/modus-stepper.component.ts +65 -0
- package/templates/angular/src/app/components/modus-switch.component.ts +118 -0
- package/templates/angular/src/app/components/modus-table.component.ts +204 -0
- package/templates/angular/src/app/components/modus-tabs.component.ts +82 -0
- package/templates/angular/src/app/components/modus-text-input.component.ts +221 -0
- package/templates/angular/src/app/components/modus-textarea.component.ts +168 -0
- package/templates/angular/src/app/components/modus-theme-switcher.component.ts +45 -0
- package/templates/angular/src/app/components/modus-time-input.component.ts +172 -0
- package/templates/angular/src/app/components/modus-toast.component.ts +63 -0
- package/templates/angular/src/app/components/modus-toolbar.component.ts +43 -0
- package/templates/angular/src/app/components/modus-tooltip.component.ts +83 -0
- package/templates/angular/src/app/components/modus-typography.component.ts +79 -0
- package/templates/angular/src/app/components/modus-utility-panel.component.ts +275 -0
- package/templates/angular/src/app/components/theme-demo.component.ts +1242 -0
- package/templates/angular/src/app/data/component-demos.ts +360 -0
- package/templates/angular/src/app/data/modus-icons.ts +806 -0
- package/templates/angular/src/app/demos/accordion/accordion-demo.component.ts +212 -0
- package/templates/angular/src/app/demos/alert/alert-demo.component.ts +108 -0
- package/templates/angular/src/app/demos/autocomplete/autocomplete-demo.component.ts +174 -0
- package/templates/angular/src/app/demos/avatar/avatar-demo.component.ts +149 -0
- package/templates/angular/src/app/demos/badge/badge-demo.component.ts +148 -0
- package/templates/angular/src/app/demos/breadcrumbs/breadcrumbs-demo.component.ts +96 -0
- package/templates/angular/src/app/demos/button/button-demo.component.ts +256 -0
- package/templates/angular/src/app/demos/button-group/button-group-demo.component.ts +215 -0
- package/templates/angular/src/app/demos/card/card-demo.component.ts +180 -0
- package/templates/angular/src/app/demos/checkbox/checkbox-demo.component.ts +71 -0
- package/templates/angular/src/app/demos/chip/chip-demo.component.ts +183 -0
- package/templates/angular/src/app/demos/date/date-demo.component.ts +193 -0
- package/templates/angular/src/app/demos/dropdown/dropdown-demo.component.ts +196 -0
- package/templates/angular/src/app/demos/file-dropzone/file-dropzone-demo.component.ts +176 -0
- package/templates/angular/src/app/demos/handle/handle-demo.component.ts +265 -0
- package/templates/angular/src/app/demos/icon/icon-demo.component.ts +65 -0
- package/templates/angular/src/app/demos/input-feedback/input-feedback-demo.component.ts +189 -0
- package/templates/angular/src/app/demos/input-label/input-label-demo.component.ts +330 -0
- package/templates/angular/src/app/demos/loader/loader-demo.component.ts +143 -0
- package/templates/angular/src/app/demos/logo/logo-demo.component.ts +191 -0
- package/templates/angular/src/app/demos/menu/menu-demo.component.ts +72 -0
- package/templates/angular/src/app/demos/modal/modal-demo.component.ts +278 -0
- package/templates/angular/src/app/demos/navbar/navbar-demo.component.ts +135 -0
- package/templates/angular/src/app/demos/number-input/number-input-demo.component.ts +175 -0
- package/templates/angular/src/app/demos/pagination/pagination-demo.component.ts +134 -0
- package/templates/angular/src/app/demos/panel/panel-demo.component.ts +235 -0
- package/templates/angular/src/app/demos/progress/progress-demo.component.ts +169 -0
- package/templates/angular/src/app/demos/radio/radio-demo.component.ts +161 -0
- package/templates/angular/src/app/demos/rating/rating-demo.component.ts +97 -0
- package/templates/angular/src/app/demos/select/select-demo.component.ts +107 -0
- package/templates/angular/src/app/demos/shared/demo-example-clean.component.ts +41 -0
- package/templates/angular/src/app/demos/shared/demo-example.component.ts +42 -0
- package/templates/angular/src/app/demos/shared/demo-page.component.ts +97 -0
- package/templates/angular/src/app/demos/shared/index.ts +3 -0
- package/templates/angular/src/app/demos/side-navigation/side-navigation-demo.component.ts +524 -0
- package/templates/angular/src/app/demos/skeleton/skeleton-demo.component.ts +112 -0
- package/templates/angular/src/app/demos/slider/slider-demo.component.ts +76 -0
- package/templates/angular/src/app/demos/stepper/stepper-demo.component.ts +79 -0
- package/templates/angular/src/app/demos/switch/switch-demo.component.ts +113 -0
- package/templates/angular/src/app/demos/table/table-demo.component.ts +405 -0
- package/templates/angular/src/app/demos/tabs/tabs-demo.component.ts +318 -0
- package/templates/angular/src/app/demos/text-input/text-input-demo.component.ts +160 -0
- package/templates/angular/src/app/demos/textarea/textarea-demo.component.ts +95 -0
- package/templates/angular/src/app/demos/theme-switcher/theme-switcher-demo.component.ts +38 -0
- package/templates/angular/src/app/demos/time-input/time-input-demo.component.ts +130 -0
- package/templates/angular/src/app/demos/toast/toast-demo.component.ts +258 -0
- package/templates/angular/src/app/demos/toolbar/toolbar-demo.component.ts +54 -0
- package/templates/angular/src/app/demos/tooltip/tooltip-demo.component.ts +163 -0
- package/templates/angular/src/app/demos/utility-panel/utility-panel-demo.component.ts +197 -0
- package/templates/angular/src/app/dev/dev-config.ts +119 -0
- package/templates/angular/src/app/dev/dev-panel/dev-panel.component.ts +215 -0
- package/templates/angular/src/app/dev/dev-panel.service.ts +63 -0
- package/templates/angular/src/app/dev/index.ts +8 -0
- package/templates/angular/src/app/dev/theme-switcher-dropdown/theme-switcher-dropdown.component.ts +134 -0
- package/templates/angular/src/app/dev-pages/color-palette/color-palette.component.ts +229 -0
- package/templates/angular/src/app/dev-pages/components-gallery/components-gallery.component.ts +486 -0
- package/templates/angular/src/app/dev-pages/icons/icons.component.ts +149 -0
- package/templates/angular/src/app/pages/home/home.component.ts +251 -0
- package/templates/angular/src/app/services/README.md +57 -0
- package/templates/angular/src/app/services/theme.service.ts +163 -0
- package/templates/angular/src/environments/environment.development.ts +8 -0
- package/templates/angular/src/environments/environment.ts +8 -0
- package/templates/angular/src/index.html +14 -0
- package/templates/angular/src/main.ts +6 -0
- package/templates/angular/src/styles.css +1328 -0
- package/templates/angular/tsconfig.app.json +15 -0
- package/templates/angular/tsconfig.json +35 -0
- package/templates/angular/tsconfig.spec.json +14 -0
- package/templates/config.json +23 -0
- package/templates/react/.cursor/commands/remove-dev-content.md +311 -0
- package/templates/react/.cursor/mcp.json +13 -0
- package/templates/react/.cursor/rules/README.md +240 -0
- package/templates/react/.cursor/rules/border-usage-guidelines-short.mdc +22 -0
- package/templates/react/.cursor/rules/border-usage-guidelines.mdc +380 -0
- package/templates/react/.cursor/rules/chrome-devtools-testing-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/development-workflow-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/development-workflow-react.mdc +292 -0
- package/templates/react/.cursor/rules/implementation-guides-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/implementation-guides-react.mdc +446 -0
- package/templates/react/.cursor/rules/modus-accordion-state-management-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-accordion-state-management-react.mdc +445 -0
- package/templates/react/.cursor/rules/modus-button-group-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-button-group-usage-react.mdc +117 -0
- package/templates/react/.cursor/rules/modus-checkbox-value-inversion-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-checkbox-value-inversion-react.mdc +492 -0
- package/templates/react/.cursor/rules/modus-color-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-color-usage-react.mdc +420 -0
- package/templates/react/.cursor/rules/modus-components-reference.mdc +366 -0
- package/templates/react/.cursor/rules/modus-icon-names.mdc +63 -0
- package/templates/react/.cursor/rules/modus-icons-react-short.mdc +24 -0
- package/templates/react/.cursor/rules/modus-icons-react.mdc +402 -0
- package/templates/react/.cursor/rules/modus-modal-implementation-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-modal-implementation-react.mdc +831 -0
- package/templates/react/.cursor/rules/modus-navbar-side-navigation-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-navbar-side-navigation-react.mdc +247 -0
- package/templates/react/.cursor/rules/modus-no-emojis-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-opacity-utilities-react-short.mdc +70 -0
- package/templates/react/.cursor/rules/modus-opacity-utilities-react.mdc +208 -0
- package/templates/react/.cursor/rules/modus-react-best-practices-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-best-practices.mdc +508 -0
- package/templates/react/.cursor/rules/modus-react-essentials.mdc +209 -0
- package/templates/react/.cursor/rules/modus-react-integration-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-integration.mdc +509 -0
- package/templates/react/.cursor/rules/modus-react-key-warnings-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-key-warnings.mdc +805 -0
- package/templates/react/.cursor/rules/modus-react-master.mdc +160 -0
- package/templates/react/.cursor/rules/modus-select-vs-dropdown-menu-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-select-vs-dropdown-menu-react.mdc +442 -0
- package/templates/react/.cursor/rules/modus-semantic-html-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-semantic-html-react.mdc +427 -0
- package/templates/react/.cursor/rules/modus-tailwind-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-tailwind-usage-react.mdc +642 -0
- package/templates/react/.cursor/rules/modus-themes-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-themes-react.mdc +506 -0
- package/templates/react/.cursor/rules/ux/gestalt-laws-detailed.mdc +456 -0
- package/templates/react/.cursor/rules/ux/ux-ui-foundations.mdc +211 -0
- package/templates/react/.cursor/skills/create-modus-form-component/SKILL.md +518 -0
- package/templates/react/.cursor/skills/create-modus-wrapper-component/SKILL.md +252 -0
- package/templates/react/.cursor/skills/fix-modus-component-event-issues/SKILL.md +345 -0
- package/templates/react/.cursor/skills/handle-modus-checkbox-value-bug/SKILL.md +202 -0
- package/templates/react/.cursor/skills/implement-modus-modal-with-refs/SKILL.md +386 -0
- package/templates/react/.cursor/skills/integrate-modus-icons/SKILL.md +300 -0
- package/templates/react/.cursor/skills/run-lint-checks/SKILL.md +235 -0
- package/templates/react/.cursor/skills/set-up-modus-event-listeners/SKILL.md +284 -0
- package/templates/react/.cursor/skills/style-modus-components-with-tailwind/SKILL.md +382 -0
- package/templates/react/.env.development +3 -0
- package/templates/react/.env.production +3 -0
- package/templates/react/.github/CODEOWNERS +28 -0
- package/templates/react/.github/ISSUE_TEMPLATE/bug_report.yml +176 -0
- package/templates/react/.github/ISSUE_TEMPLATE/config.yml +20 -0
- package/templates/react/.github/ISSUE_TEMPLATE/documentation.yml +115 -0
- package/templates/react/.github/ISSUE_TEMPLATE/feature_request.yml +171 -0
- package/templates/react/.github/ISSUE_TEMPLATE/question.yml +139 -0
- package/templates/react/.github/copilot-instructions.md +80 -0
- package/templates/react/.github/instructions/components.instructions.md +82 -0
- package/templates/react/.github/instructions/demos.instructions.md +82 -0
- package/templates/react/.github/instructions/pages.instructions.md +76 -0
- package/templates/react/.github/instructions/styles.instructions.md +77 -0
- package/templates/react/.github/instructions/typescript.instructions.md +101 -0
- package/templates/react/.github/pull_request_template.md +188 -0
- package/templates/react/.github/workflows/ci.yml +43 -0
- package/templates/react/.github/workflows/claude-code-review.yml +44 -0
- package/templates/react/.github/workflows/claude.yml +50 -0
- package/templates/react/.husky/pre-commit +28 -0
- package/templates/react/.vscode/extensions.json +8 -0
- package/templates/react/CLAUDE.md +119 -0
- package/templates/react/CODE_OF_CONDUCT.md +79 -0
- package/templates/react/CONTRIBUTING.md +65 -0
- package/templates/react/LICENSE +21 -0
- package/templates/react/README.md +728 -0
- package/templates/react/SECURITY.md +50 -0
- package/templates/react/eslint.config.js +23 -0
- package/templates/react/index.html +13 -0
- package/templates/react/package-lock.json +5209 -0
- package/templates/react/package.json +49 -0
- package/templates/react/postcss.config.js +6 -0
- package/templates/react/public/react.svg +1 -0
- package/templates/react/public/vite.svg +1 -0
- package/templates/react/readme_assets/getting_started_header.png +0 -0
- package/templates/react/readme_assets/hero.png +0 -0
- package/templates/react/readme_assets/modus_comp.png +0 -0
- package/templates/react/readme_assets/modus_figma_mcp.png +0 -0
- package/templates/react/readme_assets/teaser_comp.gif +0 -0
- package/templates/react/scripts/README.md +343 -0
- package/templates/react/scripts/check-border-violations.js +483 -0
- package/templates/react/scripts/check-icon-names.js +486 -0
- package/templates/react/scripts/check-inline-styles.js +364 -0
- package/templates/react/scripts/check-modus-colors.js +247 -0
- package/templates/react/scripts/check-modus-icons.js +256 -0
- package/templates/react/scripts/check-opacity-utilities.js +481 -0
- package/templates/react/scripts/check-semantic-html.js +476 -0
- package/templates/react/scripts/check-typescript.js +109 -0
- package/templates/react/src/App.css +42 -0
- package/templates/react/src/App.tsx +54 -0
- package/templates/react/src/assets/react.svg +1 -0
- package/templates/react/src/components/DemoExample.tsx +61 -0
- package/templates/react/src/components/DemoPage.tsx +81 -0
- package/templates/react/src/components/ModusAccordion.tsx +89 -0
- package/templates/react/src/components/ModusAlert.tsx +85 -0
- package/templates/react/src/components/ModusAutocomplete.tsx +207 -0
- package/templates/react/src/components/ModusAvatar.tsx +50 -0
- package/templates/react/src/components/ModusBadge.tsx +82 -0
- package/templates/react/src/components/ModusBreadcrumbs.tsx +75 -0
- package/templates/react/src/components/ModusButton.tsx +244 -0
- package/templates/react/src/components/ModusButtonGroup.tsx +91 -0
- package/templates/react/src/components/ModusCard.tsx +70 -0
- package/templates/react/src/components/ModusCheckbox.tsx +168 -0
- package/templates/react/src/components/ModusChip.tsx +93 -0
- package/templates/react/src/components/ModusDate.tsx +154 -0
- package/templates/react/src/components/ModusDropdownMenu.tsx +148 -0
- package/templates/react/src/components/ModusFileDropzone.tsx +140 -0
- package/templates/react/src/components/ModusHandle.tsx +101 -0
- package/templates/react/src/components/ModusIcon.tsx +49 -0
- package/templates/react/src/components/ModusInputFeedback.tsx +52 -0
- package/templates/react/src/components/ModusInputLabel.tsx +50 -0
- package/templates/react/src/components/ModusLoader.tsx +42 -0
- package/templates/react/src/components/ModusLogo.tsx +102 -0
- package/templates/react/src/components/ModusMenu.tsx +119 -0
- package/templates/react/src/components/ModusMenuItem.tsx +86 -0
- package/templates/react/src/components/ModusModal.tsx +145 -0
- package/templates/react/src/components/ModusNavbar.tsx +504 -0
- package/templates/react/src/components/ModusNumberInput.tsx +230 -0
- package/templates/react/src/components/ModusPagination.tsx +94 -0
- package/templates/react/src/components/ModusPanel.tsx +92 -0
- package/templates/react/src/components/ModusProgress.tsx +70 -0
- package/templates/react/src/components/ModusProvider.tsx +18 -0
- package/templates/react/src/components/ModusRadio.tsx +114 -0
- package/templates/react/src/components/ModusRating.tsx +108 -0
- package/templates/react/src/components/ModusSelect.tsx +171 -0
- package/templates/react/src/components/ModusSideNavigation.tsx +149 -0
- package/templates/react/src/components/ModusSkeleton.tsx +42 -0
- package/templates/react/src/components/ModusSlider.tsx +128 -0
- package/templates/react/src/components/ModusStepper.tsx +85 -0
- package/templates/react/src/components/ModusSwitch.tsx +130 -0
- package/templates/react/src/components/ModusTable.tsx +309 -0
- package/templates/react/src/components/ModusTabs.tsx +114 -0
- package/templates/react/src/components/ModusTextInput.tsx +179 -0
- package/templates/react/src/components/ModusTextarea.tsx +164 -0
- package/templates/react/src/components/ModusThemeSwitcher.tsx +58 -0
- package/templates/react/src/components/ModusTimeInput.tsx +176 -0
- package/templates/react/src/components/ModusToast.tsx +207 -0
- package/templates/react/src/components/ModusToolbar.tsx +70 -0
- package/templates/react/src/components/ModusTooltip.tsx +97 -0
- package/templates/react/src/components/ModusUtilityPanel.tsx +198 -0
- package/templates/react/src/components/ThemeSwitcherDropdown.tsx +117 -0
- package/templates/react/src/components/ThemeToggleSimple.tsx +157 -0
- package/templates/react/src/config/routes.ts +196 -0
- package/templates/react/src/contexts/ThemeContext.tsx +81 -0
- package/templates/react/src/contexts/ThemeContextData.tsx +89 -0
- package/templates/react/src/data/modusIcons.ts +865 -0
- package/templates/react/src/demos/accordion-demo/page.tsx +236 -0
- package/templates/react/src/demos/alert-demo/page.tsx +94 -0
- package/templates/react/src/demos/autocomplete-demo/page.tsx +166 -0
- package/templates/react/src/demos/avatar-demo/page.tsx +135 -0
- package/templates/react/src/demos/badge-demo/page.tsx +174 -0
- package/templates/react/src/demos/breadcrumbs-demo/page.tsx +88 -0
- package/templates/react/src/demos/button-demo/page.tsx +261 -0
- package/templates/react/src/demos/button-group-demo/page.tsx +231 -0
- package/templates/react/src/demos/card-demo/page.tsx +241 -0
- package/templates/react/src/demos/checkbox-demo/page.tsx +79 -0
- package/templates/react/src/demos/chip-demo/page.tsx +197 -0
- package/templates/react/src/demos/date-demo/page.tsx +179 -0
- package/templates/react/src/demos/dropdown-demo/page.tsx +150 -0
- package/templates/react/src/demos/file-dropzone-demo/page.tsx +186 -0
- package/templates/react/src/demos/handle-demo/page.tsx +313 -0
- package/templates/react/src/demos/icon-demo/page.tsx +72 -0
- package/templates/react/src/demos/input-feedback-demo/page.tsx +202 -0
- package/templates/react/src/demos/input-label-demo/page.tsx +392 -0
- package/templates/react/src/demos/loader-demo/page.tsx +138 -0
- package/templates/react/src/demos/logo-demo/page.tsx +292 -0
- package/templates/react/src/demos/menu-demo/page.tsx +70 -0
- package/templates/react/src/demos/modal-demo/page.tsx +332 -0
- package/templates/react/src/demos/navbar-demo/page.tsx +141 -0
- package/templates/react/src/demos/number-input-demo/page.tsx +180 -0
- package/templates/react/src/demos/pagination-demo/page.tsx +147 -0
- package/templates/react/src/demos/panel-demo/page.tsx +376 -0
- package/templates/react/src/demos/progress-demo/page.tsx +185 -0
- package/templates/react/src/demos/radio-demo/page.tsx +242 -0
- package/templates/react/src/demos/rating-demo/page.tsx +97 -0
- package/templates/react/src/demos/select-demo/page.tsx +111 -0
- package/templates/react/src/demos/side-navigation-demo/page.tsx +775 -0
- package/templates/react/src/demos/skeleton-demo/page.tsx +107 -0
- package/templates/react/src/demos/slider-demo/page.tsx +78 -0
- package/templates/react/src/demos/stepper-demo/page.tsx +86 -0
- package/templates/react/src/demos/switch-demo/page.tsx +146 -0
- package/templates/react/src/demos/table-demo/page.tsx +489 -0
- package/templates/react/src/demos/tabs-demo/page.tsx +187 -0
- package/templates/react/src/demos/text-input-demo/page.tsx +151 -0
- package/templates/react/src/demos/textarea-demo/page.tsx +73 -0
- package/templates/react/src/demos/theme-switcher-demo/page.tsx +26 -0
- package/templates/react/src/demos/time-input-demo/page.tsx +148 -0
- package/templates/react/src/demos/toast-demo/page.tsx +302 -0
- package/templates/react/src/demos/toolbar-demo/page.tsx +49 -0
- package/templates/react/src/demos/tooltip-demo/page.tsx +209 -0
- package/templates/react/src/demos/typography-test/page.tsx +28 -0
- package/templates/react/src/demos/utility-panel-demo/page.tsx +197 -0
- package/templates/react/src/dev/DevPanel.tsx +219 -0
- package/templates/react/src/dev/DevPanelContext.ts +14 -0
- package/templates/react/src/dev/DevPanelProvider.tsx +63 -0
- package/templates/react/src/dev/DevRoutes.tsx +98 -0
- package/templates/react/src/dev/config.ts +127 -0
- package/templates/react/src/dev/index.ts +8 -0
- package/templates/react/src/dev/useDevPanel.ts +17 -0
- package/templates/react/src/dev-pages/ColorPalettePage.tsx +347 -0
- package/templates/react/src/dev-pages/ComponentsGalleryPage.tsx +489 -0
- package/templates/react/src/dev-pages/IconsPage.tsx +137 -0
- package/templates/react/src/dev-pages/index.ts +3 -0
- package/templates/react/src/hooks/useTheme.ts +15 -0
- package/templates/react/src/index.css +635 -0
- package/templates/react/src/main.tsx +14 -0
- package/templates/react/src/pages/HomePage.tsx +283 -0
- package/templates/react/src/vite-env.d.ts +9 -0
- package/templates/react/tailwind.config.js +58 -0
- package/templates/react/tsconfig.app.json +27 -0
- package/templates/react/tsconfig.json +7 -0
- package/templates/react/tsconfig.node.json +25 -0
- package/templates/react/vite.config.ts +18 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Modus Icon Names Validation Script for Angular + Tailwind v4
|
|
5
|
+
*
|
|
6
|
+
* This script validates that all Modus icon names used in the codebase
|
|
7
|
+
* are correct and exist in the official Modus Icons list.
|
|
8
|
+
*
|
|
9
|
+
* It checks for typos, invalid names, and suggests corrections.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { createRequire } from 'module';
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const { glob } = require('glob');
|
|
17
|
+
|
|
18
|
+
// Read and parse the Modus icons data from TypeScript file
|
|
19
|
+
const iconsContent = fs.readFileSync(path.join(process.cwd(), 'data/modusIcons.ts'), 'utf8');
|
|
20
|
+
|
|
21
|
+
// Extract the modusIcons object using regex
|
|
22
|
+
const modusIconsMatch = iconsContent.match(/export const modusIcons = ({[\s\S]*?});/);
|
|
23
|
+
if (!modusIconsMatch) {
|
|
24
|
+
console.error('Could not extract modusIcons object from TypeScript file');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Evaluate the modusIcons object (safe since we control the content)
|
|
29
|
+
const modusIcons = eval(`(${modusIconsMatch[1]})`);
|
|
30
|
+
|
|
31
|
+
// Flatten all icons for easy access
|
|
32
|
+
const allModusIcons = Object.values(modusIcons).flat();
|
|
33
|
+
|
|
34
|
+
// File patterns to check
|
|
35
|
+
const FILE_PATTERNS = ['src/**/*.{ts,html}', 'src/**/*.css', 'src/**/*.scss'];
|
|
36
|
+
|
|
37
|
+
// Colors for console output
|
|
38
|
+
const colors = {
|
|
39
|
+
red: '\x1b[31m',
|
|
40
|
+
green: '\x1b[32m',
|
|
41
|
+
yellow: '\x1b[33m',
|
|
42
|
+
blue: '\x1b[34m',
|
|
43
|
+
magenta: '\x1b[35m',
|
|
44
|
+
cyan: '\x1b[36m',
|
|
45
|
+
white: '\x1b[37m',
|
|
46
|
+
reset: '\x1b[0m',
|
|
47
|
+
bold: '\x1b[1m',
|
|
48
|
+
dim: '\x1b[2m',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Icon usage patterns to detect (Angular template syntax)
|
|
52
|
+
const ICON_USAGE_PATTERNS = [
|
|
53
|
+
// Angular modus-icon component usage
|
|
54
|
+
/<modus-icon[^>]*name=["']([^"']+)["'][^>]*>/g,
|
|
55
|
+
|
|
56
|
+
// Direct icon class usage - match content between <i> tags with modus-icons class
|
|
57
|
+
/<i[^>]*class=["'][^"']*modus-icons[^"']*["'][^>]*>([^<]+)<\/i>/g,
|
|
58
|
+
|
|
59
|
+
// Icon in string literals - only for specific icon-related attributes
|
|
60
|
+
/icon=["']([a-zA-Z0-9_-]+)["']/g,
|
|
61
|
+
/iconName=["']([a-zA-Z0-9_-]+)["']/g,
|
|
62
|
+
/startIcon=["']([a-zA-Z0-9_-]+)["']/g,
|
|
63
|
+
/endIcon=["']([a-zA-Z0-9_-]+)["']/g,
|
|
64
|
+
|
|
65
|
+
// Angular component icon attributes
|
|
66
|
+
/<modus-button[^>]*icon=["']([^"']+)["'][^>]*>/g,
|
|
67
|
+
/<modus-card[^>]*icon=["']([^"']+)["'][^>]*>/g,
|
|
68
|
+
/<modus-chip[^>]*icon=["']([^"']+)["'][^>]*>/g,
|
|
69
|
+
/<modus-alert[^>]*icon=["']([^"']+)["'][^>]*>/g,
|
|
70
|
+
/<modus-tooltip[^>]*icon=["']([^"']+)["'][^>]*>/g,
|
|
71
|
+
|
|
72
|
+
// Icon in template literals - only if they're likely icon names
|
|
73
|
+
/`([a-zA-Z0-9_-]+)`(?=.*modus-icons)/g,
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Find similar icon names using Levenshtein distance
|
|
78
|
+
*/
|
|
79
|
+
function findSimilarIcons(iconName, maxDistance = 2) {
|
|
80
|
+
const similar = [];
|
|
81
|
+
|
|
82
|
+
for (const validIcon of allModusIcons) {
|
|
83
|
+
const distance = levenshteinDistance(iconName.toLowerCase(), validIcon.toLowerCase());
|
|
84
|
+
|
|
85
|
+
// Only include if distance is reasonable and the icon name is meaningful
|
|
86
|
+
if (distance <= maxDistance && distance > 0) {
|
|
87
|
+
// Filter out very short matches that are likely meaningless
|
|
88
|
+
if (validIcon.length >= 3 && iconName.length >= 3) {
|
|
89
|
+
similar.push({
|
|
90
|
+
name: validIcon,
|
|
91
|
+
distance: distance,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return similar.sort((a, b) => a.distance - b.distance).slice(0, 5);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Calculate Levenshtein distance between two strings
|
|
102
|
+
*/
|
|
103
|
+
function levenshteinDistance(str1, str2) {
|
|
104
|
+
const matrix = [];
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i <= str2.length; i++) {
|
|
107
|
+
matrix[i] = [i];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (let j = 0; j <= str1.length; j++) {
|
|
111
|
+
matrix[0][j] = j;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let i = 1; i <= str2.length; i++) {
|
|
115
|
+
for (let j = 1; j <= str1.length; j++) {
|
|
116
|
+
if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
|
|
117
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
118
|
+
} else {
|
|
119
|
+
matrix[i][j] = Math.min(
|
|
120
|
+
matrix[i - 1][j - 1] + 1,
|
|
121
|
+
matrix[i][j - 1] + 1,
|
|
122
|
+
matrix[i - 1][j] + 1
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return matrix[str2.length][str1.length];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Find icon by partial name match
|
|
133
|
+
*/
|
|
134
|
+
function findIconByPartial(iconName) {
|
|
135
|
+
// Only search for partial matches if the input is meaningful
|
|
136
|
+
if (iconName.length < 3) {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const partialMatches = allModusIcons.filter((icon) => {
|
|
141
|
+
// Only include icons that are at least 3 characters long
|
|
142
|
+
if (icon.length < 3) return false;
|
|
143
|
+
|
|
144
|
+
// Check if the icon name contains the search term or vice versa
|
|
145
|
+
const iconLower = icon.toLowerCase();
|
|
146
|
+
const searchLower = iconName.toLowerCase();
|
|
147
|
+
|
|
148
|
+
return iconLower.includes(searchLower) || searchLower.includes(iconLower);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Sort by relevance (exact substring matches first, then by length)
|
|
152
|
+
return partialMatches
|
|
153
|
+
.sort((a, b) => {
|
|
154
|
+
const aExact = a.toLowerCase().includes(iconName.toLowerCase());
|
|
155
|
+
const bExact = b.toLowerCase().includes(iconName.toLowerCase());
|
|
156
|
+
|
|
157
|
+
if (aExact && !bExact) return -1;
|
|
158
|
+
if (!aExact && bExact) return 1;
|
|
159
|
+
|
|
160
|
+
return a.length - b.length;
|
|
161
|
+
})
|
|
162
|
+
.slice(0, 5);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get icon category
|
|
167
|
+
*/
|
|
168
|
+
function getIconCategory(iconName) {
|
|
169
|
+
for (const [category, icons] of Object.entries(modusIcons)) {
|
|
170
|
+
if (icons.includes(iconName)) {
|
|
171
|
+
return category;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check a single file for icon name violations
|
|
179
|
+
*/
|
|
180
|
+
function checkFile(filePath) {
|
|
181
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
182
|
+
const violations = [];
|
|
183
|
+
|
|
184
|
+
for (const pattern of ICON_USAGE_PATTERNS) {
|
|
185
|
+
let match;
|
|
186
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
187
|
+
const iconName = match[1];
|
|
188
|
+
|
|
189
|
+
// Skip if it's not a potential icon name (too short, contains spaces, etc.)
|
|
190
|
+
if (
|
|
191
|
+
iconName.length < 2 ||
|
|
192
|
+
iconName.includes(' ') ||
|
|
193
|
+
iconName.includes('\n') ||
|
|
194
|
+
iconName.includes('\t')
|
|
195
|
+
) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Skip common non-icon words that might be caught by the regex
|
|
200
|
+
const commonWords = [
|
|
201
|
+
'description',
|
|
202
|
+
'title',
|
|
203
|
+
'content',
|
|
204
|
+
'text',
|
|
205
|
+
'label',
|
|
206
|
+
'value',
|
|
207
|
+
'name',
|
|
208
|
+
'id',
|
|
209
|
+
'class',
|
|
210
|
+
'type',
|
|
211
|
+
'src',
|
|
212
|
+
'alt',
|
|
213
|
+
'href',
|
|
214
|
+
'target',
|
|
215
|
+
'rel',
|
|
216
|
+
'style',
|
|
217
|
+
'width',
|
|
218
|
+
'height',
|
|
219
|
+
'size',
|
|
220
|
+
'onClick',
|
|
221
|
+
'onChange',
|
|
222
|
+
'onSubmit',
|
|
223
|
+
'onFocus',
|
|
224
|
+
'onBlur',
|
|
225
|
+
'onMouseOver',
|
|
226
|
+
'onMouseOut',
|
|
227
|
+
'className',
|
|
228
|
+
'htmlFor',
|
|
229
|
+
'ariaLabel',
|
|
230
|
+
'ariaDescribedBy',
|
|
231
|
+
'role',
|
|
232
|
+
'tabIndex',
|
|
233
|
+
'true',
|
|
234
|
+
'false',
|
|
235
|
+
'null',
|
|
236
|
+
'undefined',
|
|
237
|
+
'this',
|
|
238
|
+
'that',
|
|
239
|
+
'here',
|
|
240
|
+
'there',
|
|
241
|
+
'where',
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
if (commonWords.includes(iconName.toLowerCase())) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Check if the icon name exists in the official list
|
|
249
|
+
if (!allModusIcons.includes(iconName)) {
|
|
250
|
+
const lines = content.substring(0, match.index).split('\n');
|
|
251
|
+
const lineNumber = lines.length;
|
|
252
|
+
const columnNumber = lines[lines.length - 1].length + 1;
|
|
253
|
+
|
|
254
|
+
// Find similar icons
|
|
255
|
+
const similarIcons = findSimilarIcons(iconName);
|
|
256
|
+
const partialMatches = findIconByPartial(iconName);
|
|
257
|
+
|
|
258
|
+
violations.push({
|
|
259
|
+
file: filePath,
|
|
260
|
+
line: lineNumber,
|
|
261
|
+
column: columnNumber,
|
|
262
|
+
iconName: iconName,
|
|
263
|
+
match: match[0],
|
|
264
|
+
similarIcons: similarIcons,
|
|
265
|
+
partialMatches: partialMatches,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
pattern.lastIndex = 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return violations;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Format violation for display
|
|
277
|
+
*/
|
|
278
|
+
function formatViolation(violation) {
|
|
279
|
+
const { file, line, column, iconName, similarIcons, partialMatches } = violation;
|
|
280
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
281
|
+
|
|
282
|
+
let suggestions = [];
|
|
283
|
+
|
|
284
|
+
if (similarIcons.length > 0) {
|
|
285
|
+
suggestions.push(
|
|
286
|
+
`Did you mean: ${colors.green}${similarIcons.map((s) => s.name).join(', ')}${colors.reset}`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (partialMatches.length > 0) {
|
|
291
|
+
suggestions.push(`Similar icons: ${colors.cyan}${partialMatches.join(', ')}${colors.reset}`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
location: `${relativePath}:${line}:${column}`,
|
|
296
|
+
message: `Invalid Modus icon name: ${colors.red}${iconName}${colors.reset}`,
|
|
297
|
+
suggestions: suggestions,
|
|
298
|
+
explanation: `The icon "${iconName}" is not found in the official Modus Icons list.`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Main function
|
|
304
|
+
*/
|
|
305
|
+
async function main() {
|
|
306
|
+
console.log(`${colors.bold}${colors.blue}🔍 Validating Modus icon names...${colors.reset}\n`);
|
|
307
|
+
|
|
308
|
+
const allFiles = [];
|
|
309
|
+
for (const pattern of FILE_PATTERNS) {
|
|
310
|
+
const files = glob.sync(pattern, { cwd: process.cwd() });
|
|
311
|
+
allFiles.push(...files);
|
|
312
|
+
}
|
|
313
|
+
const uniqueFiles = [...new Set(allFiles)];
|
|
314
|
+
let totalViolations = 0;
|
|
315
|
+
const violationsByFile = {};
|
|
316
|
+
|
|
317
|
+
// Check each file
|
|
318
|
+
for (const file of uniqueFiles) {
|
|
319
|
+
const violations = checkFile(file);
|
|
320
|
+
if (violations.length > 0) {
|
|
321
|
+
violationsByFile[file] = violations;
|
|
322
|
+
totalViolations += violations.length;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Display results
|
|
327
|
+
if (totalViolations === 0) {
|
|
328
|
+
console.log(`${colors.green}✅ All Modus icon names are valid!${colors.reset}`);
|
|
329
|
+
console.log(
|
|
330
|
+
`${colors.dim}Found ${allModusIcons.length} valid Modus icons across ${
|
|
331
|
+
Object.keys(modusIcons).length
|
|
332
|
+
} categories.${colors.reset}\n`
|
|
333
|
+
);
|
|
334
|
+
process.exit(0);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
console.log(
|
|
338
|
+
`${colors.red}❌ Found ${totalViolations} invalid Modus icon name${
|
|
339
|
+
totalViolations === 1 ? '' : 's'
|
|
340
|
+
}:${colors.reset}\n`
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
// Group violations by file
|
|
344
|
+
for (const [file, violations] of Object.entries(violationsByFile)) {
|
|
345
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
346
|
+
console.log(`${colors.bold}${colors.cyan}📁 ${relativePath}${colors.reset}`);
|
|
347
|
+
|
|
348
|
+
for (const violation of violations) {
|
|
349
|
+
const formatted = formatViolation(violation);
|
|
350
|
+
console.log(` ${colors.dim}${formatted.location}${colors.reset}`);
|
|
351
|
+
console.log(` ${formatted.message}`);
|
|
352
|
+
if (formatted.suggestions.length > 0) {
|
|
353
|
+
formatted.suggestions.forEach((suggestion) => {
|
|
354
|
+
console.log(` ${suggestion}`);
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
console.log(` ${colors.dim}${formatted.explanation}${colors.reset}\n`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Summary and help
|
|
362
|
+
console.log(`${colors.bold}${colors.yellow}📋 Summary:${colors.reset}`);
|
|
363
|
+
console.log(`• Total violations: ${colors.red}${totalViolations}${colors.reset}`);
|
|
364
|
+
console.log(
|
|
365
|
+
`• Files affected: ${colors.red}${Object.keys(violationsByFile).length}${colors.reset}`
|
|
366
|
+
);
|
|
367
|
+
console.log(`• Valid icons available: ${colors.green}${allModusIcons.length}${colors.reset}\n`);
|
|
368
|
+
|
|
369
|
+
console.log(`${colors.bold}${colors.blue}💡 How to fix:${colors.reset}`);
|
|
370
|
+
console.log(`• Check the icon name spelling and case`);
|
|
371
|
+
console.log(`• Use the suggestions provided above`);
|
|
372
|
+
console.log(`• Browse available icons at: ${colors.cyan}data/modusIcons.ts${colors.reset}`);
|
|
373
|
+
console.log(`• See docs/angular-design-system.mdc for usage patterns\n`);
|
|
374
|
+
|
|
375
|
+
console.log(`${colors.bold}${colors.magenta}🔧 Available commands:${colors.reset}`);
|
|
376
|
+
console.log(`• ${colors.cyan}npm run lint:icon-names${colors.reset} - Run this check`);
|
|
377
|
+
console.log(`• ${colors.cyan}npm run lint:all${colors.reset} - Run all linting checks\n`);
|
|
378
|
+
|
|
379
|
+
// Show some popular icon categories
|
|
380
|
+
console.log(`${colors.bold}${colors.blue}📚 Popular Icon Categories:${colors.reset}`);
|
|
381
|
+
const popularCategories = [
|
|
382
|
+
'Navigation & UI',
|
|
383
|
+
'Actions & Operations',
|
|
384
|
+
'Status & Feedback',
|
|
385
|
+
'Files & Documents',
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
popularCategories.forEach((category) => {
|
|
389
|
+
const count = modusIcons[category]?.length || 0;
|
|
390
|
+
console.log(`• ${colors.cyan}${category}${colors.reset}: ${count} icons`);
|
|
391
|
+
});
|
|
392
|
+
console.log();
|
|
393
|
+
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Run the script
|
|
398
|
+
main().catch((error) => {
|
|
399
|
+
console.error(`${colors.red}❌ Error running icon names validation:${colors.reset}`);
|
|
400
|
+
console.error(error);
|
|
401
|
+
process.exit(1);
|
|
402
|
+
});
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Inline Styles Linting Script for Angular + Tailwind v4
|
|
5
|
+
*
|
|
6
|
+
* This script checks for usage of inline styles that should be replaced with Tailwind classes
|
|
7
|
+
* to ensure design system consistency and proper styling patterns.
|
|
8
|
+
*
|
|
9
|
+
* It flags common inline style patterns and suggests Tailwind alternatives.
|
|
10
|
+
*
|
|
11
|
+
* EXCEPTIONS: Border-related styles are allowed due to Tailwind v4 + Modus conflicts.
|
|
12
|
+
* However, inline border styles should be replaced with our border utility classes.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { createRequire } from 'module';
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const { glob } = require('glob');
|
|
20
|
+
|
|
21
|
+
// Inline style patterns to detect (Angular template syntax: [style.*] and style="")
|
|
22
|
+
const INLINE_STYLE_PATTERNS = [
|
|
23
|
+
// Angular style attribute binding
|
|
24
|
+
/\[style\.[^\]]+=\s*["'][^"']+["']\]/g,
|
|
25
|
+
/\[style\.[^\]]+\.px\]/g,
|
|
26
|
+
/\[style\.[^\]]+\.rem\]/g,
|
|
27
|
+
/\[style\.[^\]]+\.em\]/g,
|
|
28
|
+
/\[style\.[^\]]+\.%\]/g,
|
|
29
|
+
|
|
30
|
+
// Regular style attribute
|
|
31
|
+
/style\s*=\s*["'][^"']*background[^"']*["']/gi,
|
|
32
|
+
/style\s*=\s*["'][^"']*color[^"']*["']/gi,
|
|
33
|
+
/style\s*=\s*["'][^"']*margin[^"']*["']/gi,
|
|
34
|
+
/style\s*=\s*["'][^"']*padding[^"']*["']/gi,
|
|
35
|
+
/style\s*=\s*["'][^"']*font-size[^"']*["']/gi,
|
|
36
|
+
/style\s*=\s*["'][^"']*font-weight[^"']*["']/gi,
|
|
37
|
+
/style\s*=\s*["'][^"']*width[^"']*["']/gi,
|
|
38
|
+
/style\s*=\s*["'][^"']*height[^"']*["']/gi,
|
|
39
|
+
/style\s*=\s*["'][^"']*display[^"']*["']/gi,
|
|
40
|
+
/style\s*=\s*["'][^"']*var\(--[^"']*["']/gi,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// Tailwind alternatives for common inline styles
|
|
44
|
+
const TAILWIND_ALTERNATIVES = {
|
|
45
|
+
// Spacing (most common in Angular templates)
|
|
46
|
+
'[style.margin-right.px]="8"': 'mr-2',
|
|
47
|
+
'[style.margin-left.px]="8"': 'ml-2',
|
|
48
|
+
'[style.margin-top.px]="8"': 'mt-2',
|
|
49
|
+
'[style.margin-bottom.px]="8"': 'mb-2',
|
|
50
|
+
'[style.padding.px]="16"': 'p-4',
|
|
51
|
+
'[style.padding.px]="8"': 'p-2',
|
|
52
|
+
'[style.padding.px]="32"': 'p-8',
|
|
53
|
+
|
|
54
|
+
// Background colors - Design System Colors
|
|
55
|
+
'style="background: var(--background)"': 'bg-background',
|
|
56
|
+
'style="background: var(--card)"': 'bg-card',
|
|
57
|
+
'style="background: var(--muted)"': 'bg-muted',
|
|
58
|
+
'style="background: var(--secondary)"': 'bg-secondary',
|
|
59
|
+
'style="background: var(--primary)"': 'bg-primary',
|
|
60
|
+
'style="background: var(--success)"': 'bg-success',
|
|
61
|
+
'style="background: var(--error)"': 'bg-error',
|
|
62
|
+
'style="background: var(--warning)"': 'bg-warning',
|
|
63
|
+
|
|
64
|
+
// Text colors - Design System Colors
|
|
65
|
+
'style="color: var(--foreground)"': 'text-foreground',
|
|
66
|
+
'style="color: var(--primary)"': 'text-primary',
|
|
67
|
+
'style="color: var(--success)"': 'text-success',
|
|
68
|
+
'style="color: var(--error)"': 'text-error',
|
|
69
|
+
'style="color: var(--warning)"': 'text-warning',
|
|
70
|
+
'style="color: var(--muted-foreground)"': 'text-muted-foreground',
|
|
71
|
+
|
|
72
|
+
// Typography
|
|
73
|
+
'style="font-size: 1.5rem"': 'text-xl',
|
|
74
|
+
'style="font-size: 1.25rem"': 'text-lg',
|
|
75
|
+
'style="font-size: 1rem"': 'text-base',
|
|
76
|
+
'style="font-size: 0.875rem"': 'text-sm',
|
|
77
|
+
'style="font-size: 0.75rem"': 'text-xs',
|
|
78
|
+
'style="font-weight: 600"': 'font-semibold',
|
|
79
|
+
'style="font-weight: 700"': 'font-bold',
|
|
80
|
+
'style="text-align: center"': 'text-center',
|
|
81
|
+
'style="text-align: left"': 'text-left',
|
|
82
|
+
'style="text-align: right"': 'text-right',
|
|
83
|
+
|
|
84
|
+
// Layout
|
|
85
|
+
'style="display: flex"': 'flex',
|
|
86
|
+
'style="display: grid"': 'grid',
|
|
87
|
+
'style="display: block"': 'block',
|
|
88
|
+
'style="display: inline-block"': 'inline-block',
|
|
89
|
+
|
|
90
|
+
// Sizing
|
|
91
|
+
'style="width: 100%"': 'w-full',
|
|
92
|
+
'style="height: 100%"': 'h-full',
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Files to check
|
|
96
|
+
const FILE_PATTERNS = ['src/**/*.ts', 'src/**/*.html', 'src/**/*.css', 'src/**/*.scss'];
|
|
97
|
+
|
|
98
|
+
// Files to exclude
|
|
99
|
+
const EXCLUDE_PATTERNS = [
|
|
100
|
+
'node_modules/**',
|
|
101
|
+
'dist/**',
|
|
102
|
+
'build/**',
|
|
103
|
+
'**/*.d.ts',
|
|
104
|
+
'scripts/**',
|
|
105
|
+
'src/styles.css', // Exclude styles.css as it contains the design system definitions
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
function isBorderRelatedStyle(styleContent) {
|
|
109
|
+
// Check for border-related patterns
|
|
110
|
+
const borderPatterns = [
|
|
111
|
+
/border-width/gi,
|
|
112
|
+
/border-top/gi,
|
|
113
|
+
/border-right/gi,
|
|
114
|
+
/border-bottom/gi,
|
|
115
|
+
/border-left/gi,
|
|
116
|
+
/border:\s*["']?\d+px/gi,
|
|
117
|
+
/border:\s*["']?\d+px\s+solid/gi,
|
|
118
|
+
/border:\s*["']?\d+px\s+solid\s+var\(--border\)/gi,
|
|
119
|
+
/border:\s*["']?\d+px\s+solid\s+var\(--modus-wc-color/gi,
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
return borderPatterns.some((pattern) => pattern.test(styleContent));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isDynamicValue(styleContent) {
|
|
126
|
+
// Check for Angular template expressions
|
|
127
|
+
return (
|
|
128
|
+
styleContent.includes('{{') ||
|
|
129
|
+
styleContent.includes('}}') ||
|
|
130
|
+
(styleContent.includes('[') && styleContent.includes(']') && styleContent.includes('=')) ||
|
|
131
|
+
styleContent.includes('*ngIf') ||
|
|
132
|
+
styleContent.includes('*ngFor') ||
|
|
133
|
+
styleContent.includes('@') ||
|
|
134
|
+
styleContent.includes('?') || // Ternary operators
|
|
135
|
+
styleContent.includes('&&') || // Logical operators
|
|
136
|
+
styleContent.includes('||')
|
|
137
|
+
); // Logical operators
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getTailwindSuggestion(styleContent) {
|
|
141
|
+
// Try to find exact matches first
|
|
142
|
+
for (const [inlineStyle, tailwindClass] of Object.entries(TAILWIND_ALTERNATIVES)) {
|
|
143
|
+
if (styleContent.includes(inlineStyle)) {
|
|
144
|
+
return tailwindClass;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Generic suggestions based on common patterns
|
|
149
|
+
if (styleContent.includes('background') || styleContent.includes('background-color')) {
|
|
150
|
+
return 'Use bg-* classes (bg-background, bg-card, bg-primary, etc.)';
|
|
151
|
+
}
|
|
152
|
+
if (styleContent.includes('color')) {
|
|
153
|
+
return 'Use text-* classes (text-foreground, text-primary, etc.)';
|
|
154
|
+
}
|
|
155
|
+
if (styleContent.includes('margin')) {
|
|
156
|
+
return 'Use m-* classes (m-2, mr-4, mt-8, etc.)';
|
|
157
|
+
}
|
|
158
|
+
if (styleContent.includes('padding')) {
|
|
159
|
+
return 'Use p-* classes (p-2, px-4, py-8, etc.)';
|
|
160
|
+
}
|
|
161
|
+
if (styleContent.includes('font-size')) {
|
|
162
|
+
return 'Use text-* classes (text-sm, text-lg, text-xl, etc.)';
|
|
163
|
+
}
|
|
164
|
+
if (styleContent.includes('display')) {
|
|
165
|
+
return 'Use display classes (flex, grid, block, etc.)';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return 'Use appropriate Tailwind utility classes';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function checkFile(filePath) {
|
|
172
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
173
|
+
const violations = [];
|
|
174
|
+
|
|
175
|
+
for (const pattern of INLINE_STYLE_PATTERNS) {
|
|
176
|
+
let match;
|
|
177
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
178
|
+
const line = content.substring(0, match.index).split('\n').length;
|
|
179
|
+
const column = match.index - content.lastIndexOf('\n', match.index - 1);
|
|
180
|
+
|
|
181
|
+
const styleContent = match[0];
|
|
182
|
+
|
|
183
|
+
// Skip if it's a border-related style (allowed, but should use utilities)
|
|
184
|
+
if (isBorderRelatedStyle(styleContent)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Skip if it's a dynamic value (contains template expressions)
|
|
189
|
+
if (isDynamicValue(styleContent)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const suggestion = getTailwindSuggestion(styleContent);
|
|
194
|
+
|
|
195
|
+
violations.push({
|
|
196
|
+
file: filePath,
|
|
197
|
+
line,
|
|
198
|
+
column,
|
|
199
|
+
match: match[0],
|
|
200
|
+
message: `Inline style detected: "${match[0]}". Use Tailwind classes instead.`,
|
|
201
|
+
suggestion: suggestion,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
pattern.lastIndex = 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return violations;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function main() {
|
|
211
|
+
console.log('🎨 Checking for inline styles that should use Tailwind classes in Angular app...\n');
|
|
212
|
+
|
|
213
|
+
let allViolations = [];
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
// Get all files to check
|
|
217
|
+
const allFiles = [];
|
|
218
|
+
for (const pattern of FILE_PATTERNS) {
|
|
219
|
+
const files = glob.sync(pattern, {
|
|
220
|
+
ignore: EXCLUDE_PATTERNS,
|
|
221
|
+
});
|
|
222
|
+
allFiles.push(...files.map(f => path.resolve(f)));
|
|
223
|
+
}
|
|
224
|
+
const files = [...new Set(allFiles)];
|
|
225
|
+
|
|
226
|
+
// Check each file
|
|
227
|
+
for (const file of files) {
|
|
228
|
+
try {
|
|
229
|
+
const violations = await checkFile(file);
|
|
230
|
+
allViolations = allViolations.concat(violations);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.warn(`⚠️ Warning: Could not check file ${file}: ${error.message}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Report results
|
|
237
|
+
if (allViolations.length === 0) {
|
|
238
|
+
console.log('✅ All files are using Tailwind classes correctly!');
|
|
239
|
+
console.log(
|
|
240
|
+
'📝 Note: Border-related styles are allowed due to Tailwind v4 + Modus conflicts'
|
|
241
|
+
);
|
|
242
|
+
process.exit(0);
|
|
243
|
+
} else {
|
|
244
|
+
console.log(`❌ Found ${allViolations.length} inline style violations:\n`);
|
|
245
|
+
|
|
246
|
+
// Group violations by file
|
|
247
|
+
const violationsByFile = allViolations.reduce((acc, violation) => {
|
|
248
|
+
if (!acc[violation.file]) {
|
|
249
|
+
acc[violation.file] = [];
|
|
250
|
+
}
|
|
251
|
+
acc[violation.file].push(violation);
|
|
252
|
+
return acc;
|
|
253
|
+
}, {});
|
|
254
|
+
|
|
255
|
+
// Print violations
|
|
256
|
+
for (const [file, violations] of Object.entries(violationsByFile)) {
|
|
257
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
258
|
+
console.log(`📄 ${relativePath}:`);
|
|
259
|
+
|
|
260
|
+
for (const violation of violations) {
|
|
261
|
+
console.log(` ${violation.line}:${violation.column} - ${violation.message}`);
|
|
262
|
+
console.log(` 💡 Suggestion: ${violation.suggestion}`);
|
|
263
|
+
}
|
|
264
|
+
console.log();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log('💡 Tailwind Classes Reference:');
|
|
268
|
+
console.log(' ✅ Background: bg-background, bg-card, bg-primary, bg-muted');
|
|
269
|
+
console.log(' ✅ Text: text-foreground, text-primary, text-error');
|
|
270
|
+
console.log(' ✅ Spacing: p-4, m-2, px-4, py-2, gap-4, mr-2, ml-2');
|
|
271
|
+
console.log(' ✅ Typography: text-lg, font-semibold, text-center');
|
|
272
|
+
console.log(' ✅ Layout: flex, grid, items-center, justify-between');
|
|
273
|
+
console.log(' ✅ Sizing: w-full, h-full, max-w-5xl, min-h-screen');
|
|
274
|
+
console.log(' ✅ Effects: opacity-50, rounded-lg, shadow-lg');
|
|
275
|
+
console.log(
|
|
276
|
+
' 📝 Note: Border styles (borderWidth, border) are allowed due to Tailwind v4 conflicts'
|
|
277
|
+
);
|
|
278
|
+
console.log(
|
|
279
|
+
' 🎯 Use border utility classes: border-default, border-thick, border-dashed, etc.'
|
|
280
|
+
);
|
|
281
|
+
console.log(' 📖 Documentation: https://tailwindcss.com/docs');
|
|
282
|
+
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error('💥 Error running inline styles check:', error.message);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Run the script
|
|
292
|
+
main();
|