@corva/create-app 0.117.0 → 0.119.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 +5 -8
- package/lib/constants/manifest.js +3 -3
- package/lib/constants/package.js +43 -9
- 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 +28 -14
- 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,12 @@ 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',
|
|
35
|
-
'
|
|
33
|
+
'identity-obj-proxy': '^3.0.0',
|
|
34
|
+
'jest': '^27.4.3',
|
|
35
|
+
'jest-watch-typeahead': '^1.0.0',
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
const tsUiDevDependencies = {
|
|
@@ -124,12 +124,12 @@ const uiPackage = {
|
|
|
124
124
|
},
|
|
125
125
|
transformIgnorePatterns: [
|
|
126
126
|
'/node_modules/(?!.*@babel/runtime|@icon-park/react/es).+\\.(js|jsx|mjs|cjs|ts|tsx)$',
|
|
127
|
-
'^.+\\.
|
|
127
|
+
'^.+\\.(css|sass|scss)$',
|
|
128
128
|
],
|
|
129
129
|
modulePaths: [],
|
|
130
130
|
moduleNameMapper: {
|
|
131
131
|
'~(.*)': '<rootDir>/src/$1',
|
|
132
|
-
'^.+\\.
|
|
132
|
+
'^.+\\.(css|sass|scss)$': 'identity-obj-proxy',
|
|
133
133
|
'@corva/ui(.*)': '@corva/ui/cjs-bundle/$1',
|
|
134
134
|
},
|
|
135
135
|
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
|
|
@@ -162,16 +162,19 @@ const nodeNpmScripts = {
|
|
|
162
162
|
};
|
|
163
163
|
|
|
164
164
|
const nodeDependencies = {
|
|
165
|
-
'@corva/node-sdk': '^8.
|
|
165
|
+
'@corva/node-sdk': '^8.5.0',
|
|
166
166
|
};
|
|
167
167
|
|
|
168
168
|
const nodeDevDependencies = {
|
|
169
|
-
'@corva/eslint-config-node': '^
|
|
169
|
+
'@corva/eslint-config-node': '^6.0.0',
|
|
170
|
+
'@typescript-eslint/eslint-plugin': '^8.58.1',
|
|
171
|
+
'@typescript-eslint/parser': '^8.58.1',
|
|
170
172
|
'jest': '^29.7.0',
|
|
171
173
|
'dotenv': '^16.0.3',
|
|
172
174
|
'eslint': '^8.2.0',
|
|
175
|
+
'eslint-plugin-jest': '^27.1.5',
|
|
173
176
|
'prettier': '^2.0.0',
|
|
174
|
-
'typescript': '^5.
|
|
177
|
+
'typescript': '^5.9.3',
|
|
175
178
|
};
|
|
176
179
|
|
|
177
180
|
const nodeTsDevDependencies = {
|
|
@@ -216,6 +219,36 @@ const nodeNpmPackage = {
|
|
|
216
219
|
eslintConfig: {
|
|
217
220
|
root: true,
|
|
218
221
|
extends: '@corva/eslint-config-node',
|
|
222
|
+
overrides: [
|
|
223
|
+
{
|
|
224
|
+
files: ['**/*.ts'],
|
|
225
|
+
parser: '@typescript-eslint/parser',
|
|
226
|
+
parserOptions: {
|
|
227
|
+
project: 'tsconfig.json',
|
|
228
|
+
sourceType: 'module',
|
|
229
|
+
},
|
|
230
|
+
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
231
|
+
rules: {
|
|
232
|
+
'@typescript-eslint/padding-line-between-statements': 'off',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
files: [
|
|
237
|
+
'**/*.spec.js',
|
|
238
|
+
'**/*.spec.ts',
|
|
239
|
+
'**/*.spec.mjs',
|
|
240
|
+
'**/*.spec.cjs',
|
|
241
|
+
'**/__mocks__/**/*.js',
|
|
242
|
+
'**/__mocks__/**/*.ts',
|
|
243
|
+
'**/__mocks__/**/*.cjs',
|
|
244
|
+
'**/__mocks__/**/*.mjs',
|
|
245
|
+
],
|
|
246
|
+
plugins: ['jest'],
|
|
247
|
+
env: {
|
|
248
|
+
jest: true,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
],
|
|
219
252
|
},
|
|
220
253
|
};
|
|
221
254
|
|
|
@@ -242,7 +275,8 @@ const nodeTsYarnPackage = {
|
|
|
242
275
|
|
|
243
276
|
const extendWithTsConfig = (packageJson, version) => {
|
|
244
277
|
packageJson.devDependencies = {
|
|
245
|
-
|
|
278
|
+
// New @tsconfig/nodeX package versioning: it starts with X major version
|
|
279
|
+
[`@tsconfig/node${version}`]: `^${version}`,
|
|
246
280
|
...packageJson.devDependencies,
|
|
247
281
|
};
|
|
248
282
|
|
|
@@ -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
|
*
|
|
@@ -37,11 +39,14 @@ const checkCliVersion = async (command, version) =>
|
|
|
37
39
|
|
|
38
40
|
debug(`%s version output: %s`, command, data.toString());
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const currentVersion = semver.coerce(data.toString('utf-8'));
|
|
43
|
+
const requiredVersion = semver.coerce(semverVersionsMapping.node[version] || version);
|
|
44
|
+
|
|
45
|
+
resolve(semver.gte(currentVersion, requiredVersion));
|
|
41
46
|
});
|
|
42
47
|
});
|
|
43
48
|
|
|
44
|
-
const checkNodeVersion = (
|
|
49
|
+
const checkNodeVersion = (range) => async () => {
|
|
45
50
|
try {
|
|
46
51
|
await fs.access(`${os.homedir()}/.nvm/nvm.sh`);
|
|
47
52
|
|
|
@@ -52,7 +57,7 @@ const checkNodeVersion = (version) => async () => {
|
|
|
52
57
|
debug(e);
|
|
53
58
|
debug('nvm is not installed, checking node version');
|
|
54
59
|
|
|
55
|
-
return checkCliVersion('node',
|
|
60
|
+
return checkCliVersion('node', range);
|
|
56
61
|
}
|
|
57
62
|
};
|
|
58
63
|
|
|
@@ -60,19 +65,22 @@ export const IS_WINDOWS = process.platform === 'win32';
|
|
|
60
65
|
|
|
61
66
|
const semverVersionsMapping = {
|
|
62
67
|
node: {
|
|
63
|
-
18: '18.
|
|
64
|
-
20: '20.
|
|
65
|
-
24: '24.
|
|
68
|
+
18: '18.20.8',
|
|
69
|
+
20: '20.20.1',
|
|
70
|
+
24: '24.15.0',
|
|
66
71
|
},
|
|
67
72
|
python: {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'3.10': '3.10.9',
|
|
71
|
-
'3.11': '3.11.1',
|
|
72
|
-
'3.13': '3.13.7',
|
|
73
|
+
3.13: '3.13.13',
|
|
74
|
+
3.14: '3.14.4',
|
|
73
75
|
},
|
|
74
76
|
};
|
|
75
77
|
|
|
78
|
+
const nodeVersionRanges = {
|
|
79
|
+
18: '>=18 <19',
|
|
80
|
+
20: '>=20 <21',
|
|
81
|
+
24: '>=24 <25',
|
|
82
|
+
};
|
|
83
|
+
|
|
76
84
|
/**
|
|
77
85
|
* @typedef {Object} Runtime
|
|
78
86
|
* @property {string} language
|
|
@@ -80,17 +88,20 @@ const semverVersionsMapping = {
|
|
|
80
88
|
* @property {string} packageManager
|
|
81
89
|
* @property {string} version
|
|
82
90
|
* @property {string} semver
|
|
91
|
+
* @property {string} [enginesNode]
|
|
83
92
|
*/
|
|
84
93
|
export const resolveAppRuntime = (opts) => {
|
|
85
94
|
if (opts.appType === APP_TYPES.UI) {
|
|
86
|
-
const version =
|
|
95
|
+
const version = DEFAULT_UI_NODE_VERSION;
|
|
87
96
|
|
|
88
97
|
return {
|
|
98
|
+
environment: 'node',
|
|
89
99
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
90
|
-
isRuntimeAvailable: checkNodeVersion(
|
|
100
|
+
isRuntimeAvailable: checkNodeVersion(DEFAULT_UI_NODE_RANGE),
|
|
91
101
|
packageManager: opts.packageManager,
|
|
92
102
|
version,
|
|
93
103
|
semver: semverVersionsMapping.node[version],
|
|
104
|
+
enginesNode: DEFAULT_UI_NODE_RANGE,
|
|
94
105
|
};
|
|
95
106
|
}
|
|
96
107
|
|
|
@@ -98,17 +109,20 @@ export const resolveAppRuntime = (opts) => {
|
|
|
98
109
|
const version = /nodejs(\d{2})\.x/.exec(opts.runtime)[1];
|
|
99
110
|
|
|
100
111
|
return {
|
|
112
|
+
environment: 'node',
|
|
101
113
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
102
|
-
isRuntimeAvailable: checkNodeVersion(version),
|
|
114
|
+
isRuntimeAvailable: checkNodeVersion(nodeVersionRanges[version]),
|
|
103
115
|
packageManager: opts.packageManager,
|
|
104
116
|
version,
|
|
105
117
|
semver: semverVersionsMapping.node[version],
|
|
118
|
+
enginesNode: `^${version}`,
|
|
106
119
|
};
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
const version = /python(\d\.\d+)/.exec(opts.runtime)[1];
|
|
110
123
|
|
|
111
124
|
return {
|
|
125
|
+
environment: 'python',
|
|
112
126
|
language: 'python',
|
|
113
127
|
isRuntimeAvailable: async () => {
|
|
114
128
|
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.119.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();
|