@gallop.software/canon 2.31.0 → 2.31.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/README.md +12 -14
- package/dist/eslint/index.js +2 -2
- package/package.json +1 -1
- package/patterns/005-page-structure.md +4 -4
- package/patterns/006-block-naming.md +31 -33
- package/schema.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ import gallop from '@gallop.software/canon/eslint'
|
|
|
28
28
|
export default [
|
|
29
29
|
...nextConfig,
|
|
30
30
|
{
|
|
31
|
-
files: ['src/
|
|
31
|
+
files: ['src/app/**/_blocks/**/*.tsx', 'src/components/**/*.tsx'],
|
|
32
32
|
plugins: {
|
|
33
33
|
gallop,
|
|
34
34
|
},
|
|
@@ -66,15 +66,22 @@ rules: {
|
|
|
66
66
|
| Rule | Description |
|
|
67
67
|
|------|-------------|
|
|
68
68
|
| `gallop/no-client-blocks` | Blocks must be server components |
|
|
69
|
+
| `gallop/block-naming-convention` | Block export names must match filename |
|
|
69
70
|
| `gallop/no-container-in-section` | No Container inside Section |
|
|
70
71
|
| `gallop/prefer-component-props` | Use props over className for styles |
|
|
71
72
|
| `gallop/prefer-typography-components` | Use Paragraph/Span, not raw tags |
|
|
72
73
|
| `gallop/prefer-layout-components` | Use Grid/Columns, not raw div |
|
|
73
|
-
| `gallop/background-image-rounded` | Background images need rounded prop |
|
|
74
|
-
| `gallop/no-inline-styles` | No style attribute, use Tailwind |
|
|
75
74
|
| `gallop/no-arbitrary-colors` | Use color tokens, not arbitrary values |
|
|
75
|
+
| `gallop/no-raw-colors` | Use semantic color tokens |
|
|
76
76
|
| `gallop/no-cross-zone-imports` | Enforce import boundaries |
|
|
77
|
-
| `gallop/no-
|
|
77
|
+
| `gallop/no-native-intersection-observer` | Use react-intersection-observer |
|
|
78
|
+
| `gallop/no-component-in-blocks` | Exported components belong in /components |
|
|
79
|
+
| `gallop/prefer-list-components` | Use List/Li, not raw ul/li |
|
|
80
|
+
| `gallop/no-native-date` | Use Luxon, not native Date |
|
|
81
|
+
| `gallop/require-canon-setup` | Validate Canon ESLint configuration |
|
|
82
|
+
| `gallop/no-classnames-package` | Use clsx, not classnames |
|
|
83
|
+
| `gallop/prefer-alias-imports` | Use @/ aliases for imports |
|
|
84
|
+
| `gallop/no-inline-svg` | Use Icon component, not inline SVG |
|
|
78
85
|
|
|
79
86
|
## CLI Commands
|
|
80
87
|
|
|
@@ -87,22 +94,13 @@ npx gallop generate .cursorrules
|
|
|
87
94
|
npx gallop generate .github/copilot-instructions.md
|
|
88
95
|
```
|
|
89
96
|
|
|
90
|
-
### Validate Project Structure
|
|
91
|
-
|
|
92
|
-
Check folder structure compliance:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
npx gallop validate
|
|
96
|
-
npx gallop validate --strict # Exit code 1 on violations
|
|
97
|
-
```
|
|
98
|
-
|
|
99
97
|
### Audit Code
|
|
100
98
|
|
|
101
99
|
Check code compliance:
|
|
102
100
|
|
|
103
101
|
```bash
|
|
104
102
|
npx gallop audit
|
|
105
|
-
npx gallop audit src/
|
|
103
|
+
npx gallop audit src/ --strict
|
|
106
104
|
```
|
|
107
105
|
|
|
108
106
|
## Pattern Categories
|
package/dist/eslint/index.js
CHANGED
|
@@ -40,7 +40,7 @@ const recommended = {
|
|
|
40
40
|
const plugin = {
|
|
41
41
|
meta: {
|
|
42
42
|
name: 'eslint-plugin-gallop',
|
|
43
|
-
version: '2.
|
|
43
|
+
version: '2.31.0',
|
|
44
44
|
},
|
|
45
45
|
rules: {
|
|
46
46
|
'no-client-blocks': noClientBlocks,
|
|
@@ -68,4 +68,4 @@ const plugin = {
|
|
|
68
68
|
recommended,
|
|
69
69
|
};
|
|
70
70
|
export default plugin;
|
|
71
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXNsaW50L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sY0FBYyxNQUFNLDZCQUE2QixDQUFBO0FBQ3hELE9BQU8sb0JBQW9CLE1BQU0sb0NBQW9DLENBQUE7QUFDckUsT0FBTyxvQkFBb0IsTUFBTSxtQ0FBbUMsQ0FBQTtBQUNwRSxPQUFPLDBCQUEwQixNQUFNLHlDQUF5QyxDQUFBO0FBQ2hGLE9BQU8sc0JBQXNCLE1BQU0scUNBQXFDLENBQUE7QUFDeEUsT0FBTyxpQkFBaUIsTUFBTSxnQ0FBZ0MsQ0FBQTtBQUM5RCxPQUFPLFdBQVcsTUFBTSwwQkFBMEIsQ0FBQTtBQUNsRCxPQUFPLGtCQUFrQixNQUFNLGtDQUFrQyxDQUFBO0FBQ2pFLE9BQU8sNEJBQTRCLE1BQU0sNENBQTRDLENBQUE7QUFDckYsT0FBTyxtQkFBbUIsTUFBTSxtQ0FBbUMsQ0FBQTtBQUNuRSxPQUFPLG9CQUFvQixNQUFNLG1DQUFtQyxDQUFBO0FBQ3BFLE9BQU8sWUFBWSxNQUFNLDJCQUEyQixDQUFBO0FBQ3BELE9BQU8scUJBQXFCLE1BQU0sb0NBQW9DLENBQUE7QUFDdEUsT0FBTyxpQkFBaUIsTUFBTSxnQ0FBZ0MsQ0FBQTtBQUM5RCxPQUFPLG1CQUFtQixNQUFNLGtDQUFrQyxDQUFBO0FBQ2xFLE9BQU8sa0JBQWtCLE1BQU0saUNBQWlDLENBQUE7QUFDaEUsT0FBTyxXQUFXLE1BQU0sMEJBQTBCLENBQUE7QUFFbEQ7O0dBRUc7QUFDSCxNQUFNLFdBQVcsR0FBRztJQUNsQix5QkFBeUIsRUFBRSxNQUFNO0lBQ2pDLGdDQUFnQyxFQUFFLE1BQU07SUFDeEMsZ0NBQWdDLEVBQUUsTUFBTTtJQUN4QywrQkFBK0IsRUFBRSxNQUFNO0lBQ3ZDLHFDQUFxQyxFQUFFLE1BQU07SUFDN0MsaUNBQWlDLEVBQUUsTUFBTTtJQUN6Qyw0QkFBNEIsRUFBRSxNQUFNO0lBQ3BDLHNCQUFzQixFQUFFLE1BQU07SUFDOUIsOEJBQThCLEVBQUUsTUFBTTtJQUN0Qyx3Q0FBd0MsRUFBRSxNQUFNO0lBQ2hELCtCQUErQixFQUFFLE1BQU07SUFDdkMsK0JBQStCLEVBQUUsTUFBTTtJQUN2Qyx1QkFBdUIsRUFBRSxNQUFNO0lBQy9CLDRCQUE0QixFQUFFLE1BQU07SUFDcEMsOEJBQThCLEVBQUUsTUFBTTtJQUN0Qyw2QkFBNkIsRUFBRSxNQUFNO0lBQ3JDLHNCQUFzQixFQUFFLE1BQU07Q0FDdEIsQ0FBQTtBQUVWLE1BQU0sTUFBTSxHQUFHO0lBQ2IsSUFBSSxFQUFFO1FBQ0osSUFBSSxFQUFFLHNCQUFzQjtRQUM1QixPQUFPLEVBQUUsUUFBUTtLQUNsQjtJQUNELEtBQUssRUFBRTtRQUNMLGtCQUFrQixFQUFFLGNBQWM7UUFDbEMseUJBQXlCLEVBQUUscUJBQXFCO1FBQ2hELHlCQUF5QixFQUFFLG9CQUFvQjtRQUMvQyx3QkFBd0IsRUFBRSxvQkFBb0I7UUFDOUMsOEJBQThCLEVBQUUsMEJBQTBCO1FBQzFELDBCQUEwQixFQUFFLHNCQUFzQjtRQUNsRCxxQkFBcUIsRUFBRSxpQkFBaUI7UUFDeEMsZUFBZSxFQUFFLFdBQVc7UUFDNUIsdUJBQXVCLEVBQUUsa0JBQWtCO1FBQzNDLGlDQUFpQyxFQUFFLDRCQUE0QjtRQUMvRCx3QkFBd0IsRUFBRSxtQkFBbUI7UUFDN0Msd0JBQXdCLEVBQUUsb0JBQW9CO1FBQzlDLGdCQUFnQixFQUFFLFlBQVk7UUFDOUIscUJBQXFCLEVBQUUsaUJBQWlCO1FBQ3hDLHVCQUF1QixFQUFFLG1CQUFtQjtRQUM1QyxzQkFBc0IsRUFBRSxrQkFBa0I7UUFDMUMsZUFBZSxFQUFFLFdBQVc7S0FDN0I7SUFDRDs7O09BR0c7SUFDSCxXQUFXO0NBQ1osQ0FBQTtBQUVELGVBQWUsTUFBTSxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IG5vQ2xpZW50QmxvY2tzIGZyb20gJy4vcnVsZXMvbm8tY2xpZW50LWJsb2Nrcy5qcydcbmltcG9ydCBub0NvbnRhaW5lckluU2VjdGlvbiBmcm9tICcuL3J1bGVzL25vLWNvbnRhaW5lci1pbi1zZWN0aW9uLmpzJ1xuaW1wb3J0IHByZWZlckNvbXBvbmVudFByb3BzIGZyb20gJy4vcnVsZXMvcHJlZmVyLWNvbXBvbmVudC1wcm9wcy5qcydcbmltcG9ydCBwcmVmZXJUeXBvZ3JhcGh5Q29tcG9uZW50cyBmcm9tICcuL3J1bGVzL3ByZWZlci10eXBvZ3JhcGh5LWNvbXBvbmVudHMuanMnXG5pbXBvcnQgcHJlZmVyTGF5b3V0Q29tcG9uZW50cyBmcm9tICcuL3J1bGVzL3ByZWZlci1sYXlvdXQtY29tcG9uZW50cy5qcydcbmltcG9ydCBub0FyYml0cmFyeUNvbG9ycyBmcm9tICcuL3J1bGVzL25vLWFyYml0cmFyeS1jb2xvcnMuanMnXG5pbXBvcnQgbm9SYXdDb2xvcnMgZnJvbSAnLi9ydWxlcy9uby1yYXctY29sb3JzLmpzJ1xuaW1wb3J0IG5vQ3Jvc3Nab25lSW1wb3J0cyBmcm9tICcuL3J1bGVzL25vLWNyb3NzLXpvbmUtaW1wb3J0cy5qcydcbmltcG9ydCBub05hdGl2ZUludGVyc2VjdGlvbk9ic2VydmVyIGZyb20gJy4vcnVsZXMvbm8tbmF0aXZlLWludGVyc2VjdGlvbi1vYnNlcnZlci5qcydcbmltcG9ydCBub0NvbXBvbmVudEluQmxvY2tzIGZyb20gJy4vcnVsZXMvbm8tY29tcG9uZW50LWluLWJsb2Nrcy5qcydcbmltcG9ydCBwcmVmZXJMaXN0Q29tcG9uZW50cyBmcm9tICcuL3J1bGVzL3ByZWZlci1saXN0LWNvbXBvbmVudHMuanMnXG5pbXBvcnQgbm9OYXRpdmVEYXRlIGZyb20gJy4vcnVsZXMvbm8tbmF0aXZlLWRhdGUuanMnXG5pbXBvcnQgYmxvY2tOYW1pbmdDb252ZW50aW9uIGZyb20gJy4vcnVsZXMvYmxvY2stbmFtaW5nLWNvbnZlbnRpb24uanMnXG5pbXBvcnQgcmVxdWlyZUNhbm9uU2V0dXAgZnJvbSAnLi9ydWxlcy9yZXF1aXJlLWNhbm9uLXNldHVwLmpzJ1xuaW1wb3J0IG5vQ2xhc3NuYW1lc1BhY2thZ2UgZnJvbSAnLi9ydWxlcy9uby1jbGFzc25hbWVzLXBhY2thZ2UuanMnXG5pbXBvcnQgcHJlZmVyQWxpYXNJbXBvcnRzIGZyb20gJy4vcnVsZXMvcHJlZmVyLWFsaWFzLWltcG9ydHMuanMnXG5pbXBvcnQgbm9JbmxpbmVTdmcgZnJvbSAnLi9ydWxlcy9uby1pbmxpbmUtc3ZnLmpzJ1xuXG4vKipcbiAqIEFsbCBDYW5vbiBFU0xpbnQgcnVsZXMgd2l0aCByZWNvbW1lbmRlZCBzZXZlcml0eSBsZXZlbHNcbiAqL1xuY29uc3QgcmVjb21tZW5kZWQgPSB7XG4gICdnYWxsb3Avbm8tY2xpZW50LWJsb2Nrcyc6ICd3YXJuJyxcbiAgJ2dhbGxvcC9ibG9jay1uYW1pbmctY29udmVudGlvbic6ICd3YXJuJyxcbiAgJ2dhbGxvcC9uby1jb250YWluZXItaW4tc2VjdGlvbic6ICd3YXJuJyxcbiAgJ2dhbGxvcC9wcmVmZXItY29tcG9uZW50LXByb3BzJzogJ3dhcm4nLFxuICAnZ2FsbG9wL3ByZWZlci10eXBvZ3JhcGh5LWNvbXBvbmVudHMnOiAnd2FybicsXG4gICdnYWxsb3AvcHJlZmVyLWxheW91dC1jb21wb25lbnRzJzogJ3dhcm4nLFxuICAnZ2FsbG9wL25vLWFyYml0cmFyeS1jb2xvcnMnOiAnd2FybicsXG4gICdnYWxsb3Avbm8tcmF3LWNvbG9ycyc6ICd3YXJuJyxcbiAgJ2dhbGxvcC9uby1jcm9zcy16b25lLWltcG9ydHMnOiAnd2FybicsXG4gICdnYWxsb3Avbm8tbmF0aXZlLWludGVyc2VjdGlvbi1vYnNlcnZlcic6ICd3YXJuJyxcbiAgJ2dhbGxvcC9uby1jb21wb25lbnQtaW4tYmxvY2tzJzogJ3dhcm4nLFxuICAnZ2FsbG9wL3ByZWZlci1saXN0LWNvbXBvbmVudHMnOiAnd2FybicsXG4gICdnYWxsb3Avbm8tbmF0aXZlLWRhdGUnOiAnd2FybicsXG4gICdnYWxsb3AvcmVxdWlyZS1jYW5vbi1zZXR1cCc6ICd3YXJuJyxcbiAgJ2dhbGxvcC9uby1jbGFzc25hbWVzLXBhY2thZ2UnOiAnd2FybicsXG4gICdnYWxsb3AvcHJlZmVyLWFsaWFzLWltcG9ydHMnOiAnd2FybicsXG4gICdnYWxsb3Avbm8taW5saW5lLXN2Zyc6ICd3YXJuJyxcbn0gYXMgY29uc3RcblxuY29uc3QgcGx1Z2luID0ge1xuICBtZXRhOiB7XG4gICAgbmFtZTogJ2VzbGludC1wbHVnaW4tZ2FsbG9wJyxcbiAgICB2ZXJzaW9uOiAnMi4zMS4wJyxcbiAgfSxcbiAgcnVsZXM6IHtcbiAgICAnbm8tY2xpZW50LWJsb2Nrcyc6IG5vQ2xpZW50QmxvY2tzLFxuICAgICdibG9jay1uYW1pbmctY29udmVudGlvbic6IGJsb2NrTmFtaW5nQ29udmVudGlvbixcbiAgICAnbm8tY29udGFpbmVyLWluLXNlY3Rpb24nOiBub0NvbnRhaW5lckluU2VjdGlvbixcbiAgICAncHJlZmVyLWNvbXBvbmVudC1wcm9wcyc6IHByZWZlckNvbXBvbmVudFByb3BzLFxuICAgICdwcmVmZXItdHlwb2dyYXBoeS1jb21wb25lbnRzJzogcHJlZmVyVHlwb2dyYXBoeUNvbXBvbmVudHMsXG4gICAgJ3ByZWZlci1sYXlvdXQtY29tcG9uZW50cyc6IHByZWZlckxheW91dENvbXBvbmVudHMsXG4gICAgJ25vLWFyYml0cmFyeS1jb2xvcnMnOiBub0FyYml0cmFyeUNvbG9ycyxcbiAgICAnbm8tcmF3LWNvbG9ycyc6IG5vUmF3Q29sb3JzLFxuICAgICduby1jcm9zcy16b25lLWltcG9ydHMnOiBub0Nyb3NzWm9uZUltcG9ydHMsXG4gICAgJ25vLW5hdGl2ZS1pbnRlcnNlY3Rpb24tb2JzZXJ2ZXInOiBub05hdGl2ZUludGVyc2VjdGlvbk9ic2VydmVyLFxuICAgICduby1jb21wb25lbnQtaW4tYmxvY2tzJzogbm9Db21wb25lbnRJbkJsb2NrcyxcbiAgICAncHJlZmVyLWxpc3QtY29tcG9uZW50cyc6IHByZWZlckxpc3RDb21wb25lbnRzLFxuICAgICduby1uYXRpdmUtZGF0ZSc6IG5vTmF0aXZlRGF0ZSxcbiAgICAncmVxdWlyZS1jYW5vbi1zZXR1cCc6IHJlcXVpcmVDYW5vblNldHVwLFxuICAgICduby1jbGFzc25hbWVzLXBhY2thZ2UnOiBub0NsYXNzbmFtZXNQYWNrYWdlLFxuICAgICdwcmVmZXItYWxpYXMtaW1wb3J0cyc6IHByZWZlckFsaWFzSW1wb3J0cyxcbiAgICAnbm8taW5saW5lLXN2Zyc6IG5vSW5saW5lU3ZnLFxuICB9LFxuICAvKipcbiAgICogUmVjb21tZW5kZWQgcnVsZSBjb25maWd1cmF0aW9ucyAtIHNwcmVhZCBpbnRvIHlvdXIgRVNMaW50IGNvbmZpZ1xuICAgKiBAZXhhbXBsZSBydWxlczogeyAuLi5nYWxsb3AucmVjb21tZW5kZWQgfVxuICAgKi9cbiAgcmVjb21tZW5kZWQsXG59XG5cbmV4cG9ydCBkZWZhdWx0IHBsdWdpblxuIl19
|
package/package.json
CHANGED
|
@@ -22,14 +22,14 @@ Page files follow a consistent structure using `PageWrapper` and `generatePageMe
|
|
|
22
22
|
import { PageWrapper } from '@/components/page-wrapper'
|
|
23
23
|
import { generatePageMetadata, type PageMetadata } from '@/utils/page-helpers'
|
|
24
24
|
|
|
25
|
-
import
|
|
26
|
-
import
|
|
25
|
+
import Hero from './_blocks/hero'
|
|
26
|
+
import Services from './_blocks/services'
|
|
27
27
|
|
|
28
28
|
function Content() {
|
|
29
29
|
return (
|
|
30
30
|
<>
|
|
31
|
-
<
|
|
32
|
-
<
|
|
31
|
+
<Hero />
|
|
32
|
+
<Services />
|
|
33
33
|
</>
|
|
34
34
|
)
|
|
35
35
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## Decision
|
|
9
9
|
|
|
10
|
-
Block files are co-located in `_blocks/` subdirectories alongside page routes. Files use `
|
|
10
|
+
Block files are co-located in `_blocks/` subdirectories alongside page routes. Files use descriptive kebab-case names (`hero.tsx`, `booking.tsx`, `contact-form.tsx`). When a page has multiple blocks of the same kind, the first is `{name}.tsx` and subsequent are `{name}-2.tsx`, `{name}-3.tsx`, etc. Function exports use PascalCase.
|
|
11
11
|
|
|
12
12
|
## Rationale
|
|
13
13
|
|
|
@@ -20,9 +20,9 @@ Block files are co-located in `_blocks/` subdirectories alongside page routes. F
|
|
|
20
20
|
|
|
21
21
|
### File Names
|
|
22
22
|
|
|
23
|
-
- Lowercase with hyphens: `hero.tsx`, `
|
|
24
|
-
-
|
|
25
|
-
-
|
|
23
|
+
- Lowercase with hyphens (kebab-case): `hero.tsx`, `booking.tsx`, `contact-form.tsx`
|
|
24
|
+
- Use descriptive names that reflect the block's content or purpose
|
|
25
|
+
- When a page has multiple blocks of the same kind, the first is `{name}.tsx`, subsequent are `{name}-2.tsx`, `{name}-3.tsx`, etc.
|
|
26
26
|
- Numbering based on JSX render order in the page
|
|
27
27
|
|
|
28
28
|
### Function Exports
|
|
@@ -36,56 +36,54 @@ Block files are co-located in `_blocks/` subdirectories alongside page routes. F
|
|
|
36
36
|
|
|
37
37
|
- Use relative paths from page.tsx: `import Hero from './_blocks/hero'`
|
|
38
38
|
|
|
39
|
-
## Block
|
|
39
|
+
## Common Block Names
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Any descriptive kebab-case name is valid. These are common examples:
|
|
42
|
+
|
|
43
|
+
| Name | Description |
|
|
42
44
|
|------|-------------|
|
|
43
45
|
| `hero` | Hero/banner sections |
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `showcase` | Portfolio/gallery showcases |
|
|
47
|
-
| `cover` | Full-width image/video covers |
|
|
48
|
-
| `contact` | Contact forms and info |
|
|
46
|
+
| `call-to-action` | CTA sections |
|
|
47
|
+
| `services` | Services sections |
|
|
49
48
|
| `testimonial` | Testimonials |
|
|
49
|
+
| `cover` | Full-width image/video covers |
|
|
50
|
+
| `contact-form` | Contact forms |
|
|
51
|
+
| `contact-info` | Contact information |
|
|
52
|
+
| `overview` | Overview/intro sections |
|
|
53
|
+
| `booking` | Booking/reservation sections |
|
|
54
|
+
| `project` | Project showcase sections |
|
|
55
|
+
| `profile` | Profile/bio sections |
|
|
56
|
+
| `mission-values` | Mission and values sections |
|
|
57
|
+
| `design-philosophy` | Design philosophy sections |
|
|
58
|
+
| `accordion` | FAQ/accordion sections |
|
|
59
|
+
| `archive` | Archive/listing sections |
|
|
50
60
|
| `blog` | Blog-related sections |
|
|
51
61
|
| `pricing` | Pricing tables |
|
|
52
|
-
| `process` | Process/steps sections |
|
|
53
|
-
| `about` | About sections |
|
|
54
|
-
| `services` | Services sections |
|
|
55
|
-
| `call-to-action` | CTA sections |
|
|
56
62
|
| `partners` | Partner/logo clouds |
|
|
57
|
-
| `accordion` | FAQ/accordion sections |
|
|
58
|
-
| `archive` | Archive/listing sections |
|
|
59
|
-
| `application` | Job application forms |
|
|
60
|
-
| `business-info` | Business information |
|
|
61
|
-
| `sidebar` | Sidebar panels |
|
|
62
63
|
| `portfolio` | Portfolio grids |
|
|
63
64
|
| `form` | Form sections |
|
|
64
|
-
| `shopping` | Shopping/e-commerce sections |
|
|
65
65
|
|
|
66
66
|
## Examples
|
|
67
67
|
|
|
68
68
|
### Good
|
|
69
69
|
|
|
70
70
|
```
|
|
71
|
-
src/app/(default)/
|
|
71
|
+
src/app/(default)/contact/
|
|
72
72
|
├── page.tsx
|
|
73
73
|
└── _blocks/
|
|
74
74
|
├── hero.tsx → export default function Hero()
|
|
75
|
-
├──
|
|
76
|
-
├──
|
|
77
|
-
|
|
78
|
-
└── testimonial.tsx → export default function Testimonial()
|
|
75
|
+
├── contact-form.tsx → export default function ContactForm()
|
|
76
|
+
├── contact-info.tsx → export default function ContactInfo()
|
|
77
|
+
└── call-to-action.tsx → export default function CallToAction()
|
|
79
78
|
|
|
80
|
-
src/app/(default)/
|
|
79
|
+
src/app/(default)/portfolio/
|
|
81
80
|
├── page.tsx
|
|
82
81
|
└── _blocks/
|
|
83
82
|
├── hero.tsx → export default function Hero()
|
|
84
|
-
├──
|
|
85
|
-
├──
|
|
86
|
-
├──
|
|
87
|
-
|
|
88
|
-
└── testimonial.tsx → export default function Testimonial()
|
|
83
|
+
├── project.tsx → export default function Project()
|
|
84
|
+
├── project-2.tsx → export default function Project2()
|
|
85
|
+
├── project-3.tsx → export default function Project3()
|
|
86
|
+
└── call-to-action.tsx → export default function CallToAction()
|
|
89
87
|
```
|
|
90
88
|
|
|
91
89
|
### Bad
|
|
@@ -98,7 +96,7 @@ src/blocks/
|
|
|
98
96
|
|
|
99
97
|
src/app/(default)/furniture/_blocks/
|
|
100
98
|
├── hero-1.tsx ❌ Unnecessary number for singleton
|
|
101
|
-
├──
|
|
99
|
+
├── CTA.tsx ❌ Not kebab-case
|
|
102
100
|
```
|
|
103
101
|
|
|
104
102
|
## Enforcement
|
package/schema.json
CHANGED