@corva/create-app 0.116.0 → 0.118.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 +5 -5
- package/common/python/Makefile +8 -5
- package/common/python/pyproject.toml +25 -0
- package/common/python/uv.lock +381 -0
- package/lib/commands/create.js +5 -5
- package/lib/constants/cli.js +6 -8
- package/lib/constants/manifest.js +3 -3
- package/lib/constants/package.js +45 -8
- package/lib/flows/lib/manifest.js +1 -1
- package/lib/flows/steps/zip-file-list-resolve.js +1 -1
- package/lib/helpers/resolve-app-runtime.js +24 -12
- package/lib/helpers/utils.js +6 -2
- package/lib/main.js +2 -3
- package/package.json +8 -8
- package/templates/ui/javascript/AGENTS.md +56 -53
- package/templates/ui/javascript/src/App.completion.js +1 -1
- package/templates/ui/javascript/src/App.drilling.js +1 -1
- package/templates/ui/typescript/AGENTS.md +58 -53
- package/templates/ui/typescript/src/App.completion.tsx +1 -1
- package/templates/ui/typescript/src/App.drilling.tsx +1 -1
- package/templates/ui/typescript/src/custom.d.ts +10 -0
- package/common/python/requirements.txt +0 -2
- /package/templates/ui/javascript/src/{App.css → App.scss} +0 -0
- /package/templates/ui/typescript/src/{App.css → App.scss} +0 -0
package/lib/constants/package.js
CHANGED
|
@@ -27,12 +27,15 @@ const jsUiDevDependencies = {
|
|
|
27
27
|
'@testing-library/react': '^12.1.5',
|
|
28
28
|
'@testing-library/react-hooks': '^8.0.1',
|
|
29
29
|
'@testing-library/user-event': '^13.2.1',
|
|
30
|
-
'jest-watch-typeahead': '^1.0.0',
|
|
31
|
-
'jest': '^27.4.3',
|
|
32
30
|
'babel-jest': '^27.4.2',
|
|
33
31
|
'babel-preset-react-app': '^10.0.1',
|
|
34
32
|
'eslint': '7.32.0',
|
|
33
|
+
'identity-obj-proxy': '^3.0.0',
|
|
34
|
+
'jest': '^27.4.3',
|
|
35
|
+
'jest-watch-typeahead': '^1.0.0',
|
|
35
36
|
'postcss-loader': '4.1.0',
|
|
37
|
+
'sass': '^1.89.2',
|
|
38
|
+
'sass-loader': '^16.0.5',
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
const tsUiDevDependencies = {
|
|
@@ -124,12 +127,12 @@ const uiPackage = {
|
|
|
124
127
|
},
|
|
125
128
|
transformIgnorePatterns: [
|
|
126
129
|
'/node_modules/(?!.*@babel/runtime|@icon-park/react/es).+\\.(js|jsx|mjs|cjs|ts|tsx)$',
|
|
127
|
-
'^.+\\.
|
|
130
|
+
'^.+\\.(css|sass|scss)$',
|
|
128
131
|
],
|
|
129
132
|
modulePaths: [],
|
|
130
133
|
moduleNameMapper: {
|
|
131
134
|
'~(.*)': '<rootDir>/src/$1',
|
|
132
|
-
'^.+\\.
|
|
135
|
+
'^.+\\.(css|sass|scss)$': 'identity-obj-proxy',
|
|
133
136
|
'@corva/ui(.*)': '@corva/ui/cjs-bundle/$1',
|
|
134
137
|
},
|
|
135
138
|
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
|
|
@@ -162,16 +165,19 @@ const nodeNpmScripts = {
|
|
|
162
165
|
};
|
|
163
166
|
|
|
164
167
|
const nodeDependencies = {
|
|
165
|
-
'@corva/node-sdk': '^8.
|
|
168
|
+
'@corva/node-sdk': '^8.5.0',
|
|
166
169
|
};
|
|
167
170
|
|
|
168
171
|
const nodeDevDependencies = {
|
|
169
|
-
'@corva/eslint-config-node': '^
|
|
172
|
+
'@corva/eslint-config-node': '^6.0.0',
|
|
173
|
+
'@typescript-eslint/eslint-plugin': '^8.58.1',
|
|
174
|
+
'@typescript-eslint/parser': '^8.58.1',
|
|
170
175
|
'jest': '^29.7.0',
|
|
171
176
|
'dotenv': '^16.0.3',
|
|
172
177
|
'eslint': '^8.2.0',
|
|
178
|
+
'eslint-plugin-jest': '^27.1.5',
|
|
173
179
|
'prettier': '^2.0.0',
|
|
174
|
-
'typescript': '^5.
|
|
180
|
+
'typescript': '^5.9.3',
|
|
175
181
|
};
|
|
176
182
|
|
|
177
183
|
const nodeTsDevDependencies = {
|
|
@@ -216,6 +222,36 @@ const nodeNpmPackage = {
|
|
|
216
222
|
eslintConfig: {
|
|
217
223
|
root: true,
|
|
218
224
|
extends: '@corva/eslint-config-node',
|
|
225
|
+
overrides: [
|
|
226
|
+
{
|
|
227
|
+
files: ['**/*.ts'],
|
|
228
|
+
parser: '@typescript-eslint/parser',
|
|
229
|
+
parserOptions: {
|
|
230
|
+
project: 'tsconfig.json',
|
|
231
|
+
sourceType: 'module',
|
|
232
|
+
},
|
|
233
|
+
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
234
|
+
rules: {
|
|
235
|
+
'@typescript-eslint/padding-line-between-statements': 'off',
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
files: [
|
|
240
|
+
'**/*.spec.js',
|
|
241
|
+
'**/*.spec.ts',
|
|
242
|
+
'**/*.spec.mjs',
|
|
243
|
+
'**/*.spec.cjs',
|
|
244
|
+
'**/__mocks__/**/*.js',
|
|
245
|
+
'**/__mocks__/**/*.ts',
|
|
246
|
+
'**/__mocks__/**/*.cjs',
|
|
247
|
+
'**/__mocks__/**/*.mjs',
|
|
248
|
+
],
|
|
249
|
+
plugins: ['jest'],
|
|
250
|
+
env: {
|
|
251
|
+
jest: true,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
],
|
|
219
255
|
},
|
|
220
256
|
};
|
|
221
257
|
|
|
@@ -242,7 +278,8 @@ const nodeTsYarnPackage = {
|
|
|
242
278
|
|
|
243
279
|
const extendWithTsConfig = (packageJson, version) => {
|
|
244
280
|
packageJson.devDependencies = {
|
|
245
|
-
|
|
281
|
+
// New @tsconfig/nodeX package versioning: it starts with X major version
|
|
282
|
+
[`@tsconfig/node${version}`]: `^${version}`,
|
|
246
283
|
...packageJson.devDependencies,
|
|
247
284
|
};
|
|
248
285
|
|
|
@@ -11,7 +11,7 @@ const SCHEDULER_MAPPING = [SCHEDULER_TYPE_DATA_TIME, SCHEDULER_TYPE_DEPTH, SCHED
|
|
|
11
11
|
{},
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
-
const NODE_RUNTIMES = [APP_RUNTIMES.
|
|
14
|
+
const NODE_RUNTIMES = [APP_RUNTIMES.NODE24];
|
|
15
15
|
|
|
16
16
|
export class Manifest {
|
|
17
17
|
constructor(manifest) {
|
|
@@ -255,7 +255,7 @@ const resolveDataForZipPythonApp = async (itemsToZip = [], { manifest, dirName,
|
|
|
255
255
|
);
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
itemsToZip.push('manifest.json', 'requirements.txt');
|
|
258
|
+
itemsToZip.push('manifest.json', 'pyproject.toml', 'uv.lock', 'requirements.txt');
|
|
259
259
|
|
|
260
260
|
return {
|
|
261
261
|
zipFileName,
|
|
@@ -6,6 +6,8 @@ import os from 'os';
|
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
|
|
8
8
|
const debug = debugFn('cca:resolve-app-runtime');
|
|
9
|
+
const DEFAULT_UI_NODE_VERSION = '24';
|
|
10
|
+
const DEFAULT_UI_NODE_RANGE = '>=24 <25';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
@@ -41,7 +43,7 @@ const checkCliVersion = async (command, version) =>
|
|
|
41
43
|
});
|
|
42
44
|
});
|
|
43
45
|
|
|
44
|
-
const checkNodeVersion = (
|
|
46
|
+
const checkNodeVersion = (range) => async () => {
|
|
45
47
|
try {
|
|
46
48
|
await fs.access(`${os.homedir()}/.nvm/nvm.sh`);
|
|
47
49
|
|
|
@@ -52,7 +54,7 @@ const checkNodeVersion = (version) => async () => {
|
|
|
52
54
|
debug(e);
|
|
53
55
|
debug('nvm is not installed, checking node version');
|
|
54
56
|
|
|
55
|
-
return checkCliVersion('node',
|
|
57
|
+
return checkCliVersion('node', range);
|
|
56
58
|
}
|
|
57
59
|
};
|
|
58
60
|
|
|
@@ -60,18 +62,22 @@ export const IS_WINDOWS = process.platform === 'win32';
|
|
|
60
62
|
|
|
61
63
|
const semverVersionsMapping = {
|
|
62
64
|
node: {
|
|
63
|
-
18: '18.
|
|
64
|
-
20: '20.
|
|
65
|
+
18: '18.20.8',
|
|
66
|
+
20: '20.20.1',
|
|
67
|
+
24: '24.14.0',
|
|
65
68
|
},
|
|
66
69
|
python: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'3.10': '3.10.9',
|
|
70
|
-
'3.11': '3.11.1',
|
|
71
|
-
'3.13': '3.13.7',
|
|
70
|
+
3.13: '3.13.13',
|
|
71
|
+
3.14: '3.14.4',
|
|
72
72
|
},
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
+
const nodeVersionRanges = {
|
|
76
|
+
18: '>=18 <19',
|
|
77
|
+
20: '>=20 <21',
|
|
78
|
+
24: '>=24 <25',
|
|
79
|
+
};
|
|
80
|
+
|
|
75
81
|
/**
|
|
76
82
|
* @typedef {Object} Runtime
|
|
77
83
|
* @property {string} language
|
|
@@ -79,17 +85,20 @@ const semverVersionsMapping = {
|
|
|
79
85
|
* @property {string} packageManager
|
|
80
86
|
* @property {string} version
|
|
81
87
|
* @property {string} semver
|
|
88
|
+
* @property {string} [enginesNode]
|
|
82
89
|
*/
|
|
83
90
|
export const resolveAppRuntime = (opts) => {
|
|
84
91
|
if (opts.appType === APP_TYPES.UI) {
|
|
85
|
-
const version =
|
|
92
|
+
const version = DEFAULT_UI_NODE_VERSION;
|
|
86
93
|
|
|
87
94
|
return {
|
|
95
|
+
environment: 'node',
|
|
88
96
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
89
|
-
isRuntimeAvailable: checkNodeVersion(
|
|
97
|
+
isRuntimeAvailable: checkNodeVersion(DEFAULT_UI_NODE_RANGE),
|
|
90
98
|
packageManager: opts.packageManager,
|
|
91
99
|
version,
|
|
92
100
|
semver: semverVersionsMapping.node[version],
|
|
101
|
+
enginesNode: DEFAULT_UI_NODE_RANGE,
|
|
93
102
|
};
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -97,17 +106,20 @@ export const resolveAppRuntime = (opts) => {
|
|
|
97
106
|
const version = /nodejs(\d{2})\.x/.exec(opts.runtime)[1];
|
|
98
107
|
|
|
99
108
|
return {
|
|
109
|
+
environment: 'node',
|
|
100
110
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
101
|
-
isRuntimeAvailable: checkNodeVersion(version),
|
|
111
|
+
isRuntimeAvailable: checkNodeVersion(nodeVersionRanges[version]),
|
|
102
112
|
packageManager: opts.packageManager,
|
|
103
113
|
version,
|
|
104
114
|
semver: semverVersionsMapping.node[version],
|
|
115
|
+
enginesNode: `^${version}`,
|
|
105
116
|
};
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
const version = /python(\d\.\d+)/.exec(opts.runtime)[1];
|
|
109
120
|
|
|
110
121
|
return {
|
|
122
|
+
environment: 'python',
|
|
111
123
|
language: 'python',
|
|
112
124
|
isRuntimeAvailable: async () => {
|
|
113
125
|
if (!IS_WINDOWS) {
|
package/lib/helpers/utils.js
CHANGED
|
@@ -26,9 +26,13 @@ export const addUiAppFile = (templateFolder, root, runtime, manifest, opts) => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
export const getExcludedFiles = (manifest) => {
|
|
29
|
-
|
|
29
|
+
const excludedFiles = ['.ruff_cache', '.venv', '.pytest_cache', '__pycache__'];
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
if (manifest.isUi()) {
|
|
32
|
+
return [...excludedFiles, 'App.drilling.js', 'App.completion.js', 'App.drilling.tsx', 'App.completion.tsx'];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return excludedFiles;
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
export function copyFileSync(source, target) {
|
package/lib/main.js
CHANGED
|
@@ -17,17 +17,16 @@ import { StepError } from './flows/lib/step-error.js';
|
|
|
17
17
|
function checkNodeVersion() {
|
|
18
18
|
logger.write('Checking node version...');
|
|
19
19
|
|
|
20
|
-
const unsupportedNodeVersion = !semver.satisfies(process.version, '>=
|
|
20
|
+
const unsupportedNodeVersion = !semver.satisfies(process.version, '>=24 <25');
|
|
21
21
|
|
|
22
22
|
if (unsupportedNodeVersion) {
|
|
23
23
|
logger.log(
|
|
24
24
|
chalk.red(
|
|
25
25
|
`\nYou are using Node ${process.version}.\n\n` +
|
|
26
|
-
`Please update to Node
|
|
26
|
+
`Please update to Node 24.x for a better, fully supported experience.\n`,
|
|
27
27
|
),
|
|
28
28
|
);
|
|
29
29
|
|
|
30
|
-
// Fall back to latest supported react-scripts on Node 4
|
|
31
30
|
return process.exit(1);
|
|
32
31
|
}
|
|
33
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corva/create-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.118.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Create an app to use it in CORVA.AI",
|
|
6
6
|
"keywords": [
|
|
@@ -70,18 +70,18 @@
|
|
|
70
70
|
"@commitlint/cli": "^17.3.0",
|
|
71
71
|
"@commitlint/config-conventional": "^17.3.0",
|
|
72
72
|
"@corva/eslint-config-browser": "^0.1.7",
|
|
73
|
-
"@corva/eslint-config-node": "^
|
|
74
|
-
"@corva/node-sdk": "^8.0
|
|
73
|
+
"@corva/eslint-config-node": "^6.0.0",
|
|
74
|
+
"@corva/node-sdk": "^8.5.0",
|
|
75
75
|
"@types/cross-spawn": "^6.0.2",
|
|
76
76
|
"@types/jest": "^29.5.4",
|
|
77
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
78
|
-
"@typescript-eslint/parser": "^
|
|
77
|
+
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
78
|
+
"@typescript-eslint/parser": "^8.58.1",
|
|
79
79
|
"conventional-changelog-cli": "^2.1.0",
|
|
80
80
|
"eslint": "^8.2.0",
|
|
81
|
+
"eslint-plugin-jest": "^27.1.5",
|
|
81
82
|
"eslint-config-google": "^0.14.0",
|
|
82
83
|
"eslint-config-prettier": "^8.5.0",
|
|
83
84
|
"eslint-plugin-import": "^2.26.0",
|
|
84
|
-
"eslint-plugin-jest": "^27.1.5",
|
|
85
85
|
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
86
86
|
"eslint-plugin-prettier": "^4.2.1",
|
|
87
87
|
"eslint-plugin-react": "^7.32.0",
|
|
@@ -92,12 +92,12 @@
|
|
|
92
92
|
"prettier": "^2.0.0",
|
|
93
93
|
"prettier-plugin-packagejson": "^2.3.0",
|
|
94
94
|
"standard-version": "^9.0.0",
|
|
95
|
-
"typescript": "^
|
|
95
|
+
"typescript": "^5.9.3",
|
|
96
96
|
"zx": "^7.2.3"
|
|
97
97
|
},
|
|
98
98
|
"packageManager": "yarn@1.22.19+sha512.ff4579ab459bb25aa7c0ff75b62acebe576f6084b36aa842971cf250a5d8c6cd3bc9420b22ce63c7f93a0857bc6ef29291db39c3e7a23aab5adfd5a4dd6c5d71",
|
|
99
99
|
"engines": {
|
|
100
|
-
"node": ">=
|
|
100
|
+
"node": ">=24 <25"
|
|
101
101
|
},
|
|
102
102
|
"standard-version": {
|
|
103
103
|
"skip": {
|
|
@@ -20,7 +20,7 @@ src/
|
|
|
20
20
|
AppSettings.js — Settings panel component (default export required)
|
|
21
21
|
index.js — Root export: { component, settings }
|
|
22
22
|
constants.js — Default settings values
|
|
23
|
-
App.
|
|
23
|
+
App.scss — Component styles
|
|
24
24
|
__tests__/ — Jest test files
|
|
25
25
|
__mocks__/ — Mock data (mockAppProps.js, mockAppSettingsProps.js)
|
|
26
26
|
assets/ — Static assets (SVGs, images)
|
|
@@ -38,83 +38,86 @@ manifest.json — Corva platform app metadata (generated at scaffold ti
|
|
|
38
38
|
|
|
39
39
|
### Styling
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
The preferred way to write styles is SCSS (`.scss` files).
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
Every `.scss` file must import the shared utilities:
|
|
44
|
+
|
|
45
|
+
```scss
|
|
46
|
+
@import '@corva/ui/styles/common';
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
This provides all functions, variables, and mixins below.
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
51
|
+
For custom shared variables or mixins specific to the project, create a `src/styles/` directory (e.g. `_variables.scss`, `_common.scss`) and import them alongside the `@corva/ui` import.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
root: { display: 'flex', gap: theme.spacing(1) },
|
|
55
|
-
}));
|
|
53
|
+
**`spacing($top, $right?, $bottom?, $left?)`** — 8px base unit:
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
```scss
|
|
56
|
+
padding: spacing(2); // 16px
|
|
57
|
+
margin: spacing(1, 0); // 8px 0
|
|
58
|
+
gap: spacing(0.5); // 4px
|
|
59
|
+
padding: spacing(2, 1, 2, 1); // 16px 8px 16px 8px
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
**`
|
|
62
|
+
**`colorAlpha($color, $opacity)`** — transparency:
|
|
63
63
|
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
borderRadius: theme.spacing(0.5); // 4px
|
|
64
|
+
```scss
|
|
65
|
+
background: colorAlpha($palette_t1, 0.08); // white at 8% opacity
|
|
66
|
+
border: 1px solid colorAlpha($palette_t1, 0.12);
|
|
68
67
|
```
|
|
69
68
|
|
|
70
|
-
|
|
69
|
+
**`transition($properties...)`** — standard `cubic-bezier(0.4, 0, 0.2, 1) 0.15s`:
|
|
71
70
|
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
background: fade(theme.palette.common.white, 0.08); // white at 8% opacity
|
|
76
|
-
color: darken(theme.palette.primary.main, 0.2); // darken by 20%
|
|
71
|
+
```scss
|
|
72
|
+
transition: transition(opacity);
|
|
73
|
+
transition: transition(color, background-color);
|
|
77
74
|
```
|
|
78
75
|
|
|
79
|
-
**
|
|
76
|
+
**Full example:**
|
|
80
77
|
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
```scss
|
|
79
|
+
@import '@corva/ui/styles/common';
|
|
80
|
+
|
|
81
|
+
.container {
|
|
82
|
+
padding: spacing(2);
|
|
83
|
+
background: $palette_b5;
|
|
84
|
+
color: $palette_t1;
|
|
85
|
+
transition: transition(opacity, background-color);
|
|
86
|
+
|
|
87
|
+
&:hover {
|
|
88
|
+
background: colorAlpha($palette_t1, 0.08);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.label {
|
|
93
|
+
color: $palette_t7;
|
|
94
|
+
font-size: 12px;
|
|
95
|
+
}
|
|
86
96
|
```
|
|
87
97
|
|
|
88
|
-
**
|
|
98
|
+
**Import in component:**
|
|
89
99
|
|
|
90
100
|
```javascript
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
import styles from './App.scss';
|
|
102
|
+
// Use: <div className={styles.container}>
|
|
93
103
|
```
|
|
94
104
|
|
|
95
|
-
|
|
105
|
+
**Colors & Theming:**
|
|
96
106
|
|
|
97
|
-
|
|
107
|
+
NEVER hardcode color values (hex, rgb, hsl). Always use `@corva/ui` theme colors:
|
|
98
108
|
|
|
99
|
-
|
|
100
|
-
color
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```
|
|
109
|
+
- In SCSS: use SCSS variables from `@corva/ui/styles/common` like `$palette_t1`, `$palette_b5`, `$palette_t7`
|
|
110
|
+
- Use `colorAlpha($color, $opacity)` for transparency instead of raw `rgba()`
|
|
111
|
+
- Run MCP tool `get_theme_docs` (section: "variables") to see all available theme variables
|
|
112
|
+
- Run MCP tool `get_theme_docs` (section: "palette") to see available palette colors with hex values
|
|
104
113
|
|
|
105
|
-
**
|
|
114
|
+
**Rules:**
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
**Direct theme import:**
|
|
114
|
-
|
|
115
|
-
```javascript
|
|
116
|
-
import { lightTheme, darkTheme } from '@corva/ui/config';
|
|
117
|
-
```
|
|
116
|
+
- No inline `style={{...}}` unless absolutely necessary for dynamic values
|
|
117
|
+
- Use `classnames` for conditional/composed classes, never manual string joins
|
|
118
|
+
- No global selectors (tag selectors like `div`, `span`) — use `:global()` only when absolutely necessary
|
|
119
|
+
- No `!important`
|
|
120
|
+
- Use a descriptive camelCase class as the root selector (e.g. `.toolbar`, `.chartPanel`) instead of generic `.root`
|
|
118
121
|
|
|
119
122
|
### State Management (Zustand)
|
|
120
123
|
|
|
@@ -4,7 +4,7 @@ import { useAppCommons } from '@corva/ui/effects';
|
|
|
4
4
|
import { DEFAULT_SETTINGS } from './constants';
|
|
5
5
|
import logo from './assets/logo.svg';
|
|
6
6
|
|
|
7
|
-
import styles from './App.
|
|
7
|
+
import styles from './App.scss';
|
|
8
8
|
|
|
9
9
|
const App = () => {
|
|
10
10
|
const { appKey, fracFleet, well, wells, appSettings } = useAppCommons();
|
|
@@ -4,7 +4,7 @@ import { useAppCommons } from '@corva/ui/effects';
|
|
|
4
4
|
import { DEFAULT_SETTINGS } from './constants';
|
|
5
5
|
import logo from './assets/logo.svg';
|
|
6
6
|
|
|
7
|
-
import styles from './App.
|
|
7
|
+
import styles from './App.scss';
|
|
8
8
|
|
|
9
9
|
const App = () => {
|
|
10
10
|
const { appKey, rig, well, appSettings } = useAppCommons();
|
|
@@ -22,7 +22,7 @@ src/
|
|
|
22
22
|
constants.ts — Default settings values
|
|
23
23
|
types.ts — Custom app settings interface
|
|
24
24
|
custom.d.ts — Module declarations for CSS/SVG imports
|
|
25
|
-
App.
|
|
25
|
+
App.scss — Component styles (SCSS modules)
|
|
26
26
|
__tests__/ — Jest test files
|
|
27
27
|
__mocks__/mockData.ts — Mock data for tests
|
|
28
28
|
assets/ — Static assets (SVGs, images)
|
|
@@ -57,83 +57,86 @@ const AppSettings = () => {
|
|
|
57
57
|
|
|
58
58
|
### Styling
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
The preferred way to write styles is SCSS (`.scss` files).
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
Every `.scss` file must import the shared utilities:
|
|
63
|
+
|
|
64
|
+
```scss
|
|
65
|
+
@import '@corva/ui/styles/common';
|
|
65
66
|
```
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
This provides all functions, variables, and mixins below.
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
import { makeStyles } from '@material-ui/core/styles';
|
|
70
|
+
For custom shared variables or mixins specific to the project, create a `src/styles/` directory (e.g. `_variables.scss`, `_common.scss`) and import them alongside the `@corva/ui` import.
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
root: { display: 'flex', gap: theme.spacing(1) },
|
|
74
|
-
}));
|
|
72
|
+
**`spacing($top, $right?, $bottom?, $left?)`** — 8px base unit:
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
```scss
|
|
75
|
+
padding: spacing(2); // 16px
|
|
76
|
+
margin: spacing(1, 0); // 8px 0
|
|
77
|
+
gap: spacing(0.5); // 4px
|
|
78
|
+
padding: spacing(2, 1, 2, 1); // 16px 8px 16px 8px
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
**`
|
|
81
|
+
**`colorAlpha($color, $opacity)`** — transparency:
|
|
82
82
|
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
borderRadius: theme.spacing(0.5) // 4px
|
|
83
|
+
```scss
|
|
84
|
+
background: colorAlpha($palette_t1, 0.08); // white at 8% opacity
|
|
85
|
+
border: 1px solid colorAlpha($palette_t1, 0.12);
|
|
87
86
|
```
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
import { fade, darken, lighten } from '@material-ui/core/styles';
|
|
88
|
+
**`transition($properties...)`** — standard `cubic-bezier(0.4, 0, 0.2, 1) 0.15s`:
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
```scss
|
|
91
|
+
transition: transition(opacity);
|
|
92
|
+
transition: transition(color, background-color);
|
|
96
93
|
```
|
|
97
94
|
|
|
98
|
-
**
|
|
95
|
+
**Full example:**
|
|
99
96
|
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
```scss
|
|
98
|
+
@import '@corva/ui/styles/common';
|
|
99
|
+
|
|
100
|
+
.container {
|
|
101
|
+
padding: spacing(2);
|
|
102
|
+
background: $palette_b5;
|
|
103
|
+
color: $palette_t1;
|
|
104
|
+
transition: transition(opacity, background-color);
|
|
105
|
+
|
|
106
|
+
&:hover {
|
|
107
|
+
background: colorAlpha($palette_t1, 0.08);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.label {
|
|
112
|
+
color: $palette_t7;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
105
115
|
```
|
|
106
116
|
|
|
107
|
-
**
|
|
117
|
+
**Import in component:**
|
|
108
118
|
|
|
109
119
|
```typescript
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
import styles from './App.scss';
|
|
121
|
+
// Use: <div className={styles.container}>
|
|
112
122
|
```
|
|
113
123
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
**CSS variables** — available in `.css` files:
|
|
124
|
+
**Colors & Theming:**
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
color: var(--palette-primary-text-1); /* primary text */
|
|
120
|
-
background: var(--palette-background-b-5); /* card background */
|
|
121
|
-
border-color: var(--palette-primary-text-9); /* borders */
|
|
122
|
-
```
|
|
126
|
+
NEVER hardcode color values (hex, rgb, hsl). Always use `@corva/ui` theme colors:
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
- In SCSS: use SCSS variables from `@corva/ui/styles/common` like `$palette_t1`, `$palette_b5`, `$palette_t7`
|
|
129
|
+
- Use `colorAlpha($color, $opacity)` for transparency instead of raw `rgba()`
|
|
130
|
+
- Run MCP tool `get_theme_docs` (section: "variables") to see all available theme variables
|
|
131
|
+
- Run MCP tool `get_theme_docs` (section: "palette") to see available palette colors with hex values
|
|
125
132
|
|
|
126
|
-
|
|
127
|
-
padding: spacing(2); // 16px
|
|
128
|
-
color: colorAlpha($color, 0.5); // rgba transparency
|
|
129
|
-
transition: transition(opacity); // standard cubic-bezier
|
|
130
|
-
```
|
|
133
|
+
**Rules:**
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
- No inline `style={{...}}` unless absolutely necessary for dynamic values
|
|
136
|
+
- Use `classnames` for conditional/composed classes, never manual string joins
|
|
137
|
+
- No global selectors (tag selectors like `div`, `span`) — use `:global()` only when absolutely necessary
|
|
138
|
+
- No `!important`
|
|
139
|
+
- Use a descriptive camelCase class as the root selector (e.g. `.toolbar`, `.chartPanel`) instead of generic `.root`
|
|
137
140
|
|
|
138
141
|
### State Management (Zustand)
|
|
139
142
|
|
|
@@ -216,6 +219,7 @@ const selectedChannels = useAppStoreSelector(state => state.selectedChannels);
|
|
|
216
219
|
**Wire it up in `ParentApp`** (see full example with `QueryClientProvider` in the Data Fetching section below).
|
|
217
220
|
|
|
218
221
|
General rules:
|
|
222
|
+
|
|
219
223
|
- Name stores `use[Name]Store` (e.g., `useWellDataStore`)
|
|
220
224
|
- Use selectors: `const value = useAppStore('value')`
|
|
221
225
|
- Keep business logic in store actions
|
|
@@ -277,6 +281,7 @@ export default { component: ParentApp, settings: AppSettings };
|
|
|
277
281
|
```
|
|
278
282
|
|
|
279
283
|
General rules:
|
|
284
|
+
|
|
280
285
|
- Encapsulate queries in custom hooks (e.g., `useWellData`)
|
|
281
286
|
- Use typed query keys (array format)
|
|
282
287
|
- Always handle `isLoading` and `isError` states
|
|
@@ -4,7 +4,7 @@ import { useAppCommons } from '@corva/ui/effects';
|
|
|
4
4
|
import { DEFAULT_SETTINGS } from './constants';
|
|
5
5
|
import logo from './assets/logo.svg';
|
|
6
6
|
|
|
7
|
-
import styles from './App.
|
|
7
|
+
import styles from './App.scss';
|
|
8
8
|
|
|
9
9
|
const App = () => {
|
|
10
10
|
const { appKey, fracFleet, well, wells, appSettings } = useAppCommons();
|
|
@@ -4,7 +4,7 @@ import { useAppCommons } from '@corva/ui/effects';
|
|
|
4
4
|
import { DEFAULT_SETTINGS } from './constants';
|
|
5
5
|
import logo from './assets/logo.svg';
|
|
6
6
|
|
|
7
|
-
import styles from './App.
|
|
7
|
+
import styles from './App.scss';
|
|
8
8
|
|
|
9
9
|
const App = () => {
|
|
10
10
|
const { appKey, rig, well, appSettings } = useAppCommons();
|