@massimo-cassandro/minimo 1.32.0 → 1.32.2

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.
@@ -3,17 +3,19 @@
3
3
  **/*.mwb.bak
4
4
  **/*.mwb.beforefix
5
5
 
6
- vendor
7
6
 
8
- # local env
9
- # .env
10
- .env.dev
7
+ ###> symfony/framework-bundle ###
11
8
  .env.local
12
- .env.development
13
- .env.test
14
- .env.development.local
15
- .env.test.local
16
- .env.production.local
9
+ .env.dev
10
+ /.env.local.php
11
+ /.env.*.local
12
+ /config/secrets/prod/prod.decrypt.private.php
13
+ /public/bundles/
14
+ /config/reference.php
15
+ /var/
16
+ /vendor/
17
+ ###< symfony/framework-bundle ###
18
+
17
19
 
18
20
  # frontend
19
21
  node_modules
@@ -14,7 +14,7 @@
14
14
  "@icons/*": ["app/icons/*"],
15
15
  "@imgs/*": ["app/imgs/*"],
16
16
 
17
- "@frontend/*": ["fromtend/*"],
17
+ "@app/*": ["app/*"],
18
18
 
19
19
  "@minimo/*": ["./node_modules/@massimo-cassandro/minimo/src/*"],
20
20
  "@minimoCharts/*": ["./node_modules/@massimo-cassandro/minimo/charts/*"]
@@ -180,16 +180,17 @@ if [ "$DEBUG" = "TRUE" ]; then
180
180
  devDependencies=()
181
181
  fi
182
182
 
183
- for pkg in "${dependencies[@]}"; do
183
+ for pkg in "${devDependencies[@]}"; do
184
184
  echo -e "${DIM}...installing "$pkg"${NC}"
185
- npm i -S "$pkg"
185
+ npm i -D "$pkg"
186
186
  done
187
187
 
188
- for pkg in "${devDependencies[@]}"; do
188
+ for pkg in "${dependencies[@]}"; do
189
189
  echo -e "${DIM}...installing "$pkg"${NC}"
190
- npm i -D "$pkg"
190
+ npm i -S "$pkg"
191
191
  done
192
192
 
193
+
193
194
  echo -e "\n${GREEN}...creating default folders${NC}"
194
195
  mkdir -p \
195
196
  "${FRONTEND_INSTALL_PATH}/src" \
@@ -36,31 +36,36 @@ const fromProjectRoot = (relPath) => {
36
36
  };
37
37
 
38
38
  const isDevelopment = process.env.NODE_ENV === 'development'
39
- ,devServerPort = 5704
40
- // ,apiPort = 8104
39
+ ,devServerPort = 570x
40
+ // ,apiPort = 800x
41
41
  ,useSass = false
42
42
  ,inlineCssInDevMode = true
43
43
  ,useSvgo = true
44
44
  ,useSvgr = false // svg per react
45
45
  ,svgoConfig = useSvgo? (await import('./webpack-config-modules/svgo.config.mjs')).default : null
46
46
  ,postcssConfig_path = path.resolve(__dirname, './webpack-config-modules/postcss.config.mjs')
47
+
47
48
  // dir di output: relativa a QUESTO file ('../build' se il frontend è in una
48
49
  // sottodirectory, './build' se webpack.config.mjs è nella root del progetto)
49
50
  ,output_dir = path.resolve(__dirname, './build')
50
51
  // ,output_dir = isDevelopment? '_dev' : 'build' // symfony
52
+
51
53
  // dir delle favicons generate da `npx create-favicons` (vedi package.json):
52
54
  // il path assoluto serve a CopyWebpackPlugin/HtmlWebpackPlugin (i path
53
55
  // relativi sarebbero risolti dal cwd, non da questo file), mentre la regexp
54
56
  // resta relativa perché viene confrontata con i path dei moduli
55
- ,favicons_path = path.resolve(__dirname, './app/favicons/output')
57
+ ,favicons_path = path.resolve(__dirname, './app/favicons/output') // commentare se non usato
56
58
  ,favicons_path_regexp = /favicons\/output/ // source pattern per le favicons (regexp o null)
59
+
57
60
  // NB: jsconfig.json va tenuto in questa stessa dir (gli alias sono risolti
58
61
  // a partire dalla sua posizione)
59
62
  ,jsConfigAliases = getJsConfigAliases(path.resolve(__dirname, './jsconfig.json'))
60
63
  ,packageJson = JSON.parse(fs.readFileSync(fromProjectRoot('package.json'), 'utf-8'))
64
+
61
65
  // path del pacchetto minimo (il suo js genera markup con classi proprie e il
62
66
  // suo css dichiara custom properties: entrambi vanno visti da PurgeCSS)
63
67
  ,minimo_path = fromProjectRoot('node_modules/@massimo-cassandro/minimo')
68
+
64
69
  ,usePurgeCss = true // false per disattivare PurgeCSS (debug rapido di problemi legati al purge)
65
70
  ,purgeCSSOptions = {
66
71
  variables: false, // rimuove le custom properties non usate (sostituisce jit-props)
@@ -113,10 +118,7 @@ const shared_chunk_paths = (module) => {
113
118
  // (null o array vuoto per disattivare)
114
119
  // https://github.com/webpack/copy-webpack-plugin/tree/main?tab=readme-ov-file#copy-webpack-plugin
115
120
  const CopyWebpackPluginPatterns = [
116
- {
117
- from: `${favicons_path}/icon-*.png`,
118
- to: '[name][ext]'
119
- },
121
+
120
122
  // {
121
123
  // from: '*.webp',
122
124
  // to: 'imgs/[name].[contenthash].[ext]',
@@ -128,7 +130,7 @@ const CopyWebpackPluginPatterns = [
128
130
  // }
129
131
  // },
130
132
  // {
131
- // from: 'src/php',
133
+ // from: 'app/php',
132
134
  // to: 'php',
133
135
  // globOptions: {
134
136
  // dot: true,
@@ -199,11 +201,11 @@ const config = {
199
201
 
200
202
  /* SYMFONY:
201
203
  output: {
202
- path: path.resolve(__dirname, `../public/${output_dir}` ),
204
+ path: path.resolve(__dirname, `./public/${output_dir}` ),
203
205
  // filename: '[name].js',
204
206
  filename: '[name].[contenthash].js',
205
207
  publicPath: `/${output_dir}/`,
206
- clean: false //!isDevelopment,
208
+ clean: !isDevelopment || !!process.env.WEBPACK_SERVE,
207
209
  },
208
210
  */
209
211
 
@@ -259,17 +261,44 @@ const config = {
259
261
  compress: true,
260
262
  hot: true,
261
263
  port: devServerPort,
262
- /*
263
- proxy: [
264
- {
265
- context: ['/api'],
266
- target: process.env.API_URL || `http://localhost:${apiPort}`
267
- }
268
- ],
269
- static: false,
270
- */
264
+ client: { overlay: true, },
271
265
  },
272
266
 
267
+ // =>> devServer (con symfony)
268
+ // reverse proxy davanti a `symfony serve` (porta 8102, vedi package.json):
269
+ // il browser va aperto su questo dev server (non su :8102). Le richieste per
270
+ // gli asset (path che iniziano per output.publicPath, es. /_dev/*) vengono
271
+ // servite da webpack (in memoria, con HMR); tutto il resto (pagine Twig,
272
+ // route Symfony, chiamate ajax con url relativi) viene proxato a Symfony.
273
+ // Symfony resta un processo separato e ignaro del dev server: continua a
274
+ // risolvere asset() leggendo manifest.json da disco, per questo serve
275
+ // devMiddleware.writeToDisk: true (vedi anche `output.clean` sopra, sempre
276
+ // false in dev per non ripulire il manifest tra una build e l'altra)
277
+ // devServer: {
278
+ // host: '0.0.0.0', // come symfony serve --listen-ip=0.0.0.0
279
+ // port: devServerPort,
280
+ // allowedHosts: 'all', // necessario per accesso da altri device in LAN
281
+ // // senza contenthash (vedi output.filename / MiniCssExtractPlugin sopra) i
282
+ // // filename restano stabili tra una modifica e l'altra: impedisce al browser
283
+ // // di servire una versione stale in cache su reload manuale
284
+ // headers: { 'Cache-Control': 'no-store' },
285
+ // hot: true,
286
+ // open: { app: { name: 'Google Chrome' } }, // apertura automatica del browser all'avvio
287
+ // static: false, // niente static serving proprio: tutto il resto passa dal proxy verso Symfony
288
+ // devMiddleware: { writeToDisk: true, },
289
+ // client: { overlay: true, },
290
+ // proxy: [
291
+ // {
292
+ // context: ['**'], // ['/api'],
293
+ // target: process.env.API_URL || `http://localhost:${apiPort}`
294
+ // // NON impostare changeOrigin: deve restare l'Host visto dal browser
295
+ // // (questo dev server), altrimenti gli url assoluti eventualmente
296
+ // // generati da Symfony (redirect, form action, ecc.) punterebbero a
297
+ // // `:${apiPort}` invece che a questo dev server
298
+ // }
299
+ // ],
300
+ // },
301
+
273
302
  // =>> plugins
274
303
  plugins: [
275
304
  // =>> plugins: Dotenv
@@ -332,7 +361,7 @@ const config = {
332
361
  // =>> plugins: HtmlWebpackPlugin
333
362
  new HtmlWebpackPlugin({
334
363
  filename: 'index.html',
335
- template: path.resolve(__dirname, './src/tpl/index.ejs'),
364
+ template: path.resolve(__dirname, './app/tpl/index.ejs'),
336
365
  inject: 'body',
337
366
  title: 'XXXXX',
338
367
  minify: !isDevelopment
@@ -420,12 +449,12 @@ const config = {
420
449
  // progetti symfony: template twig e classi generate lato php
421
450
  // (percorsi relativi alla root del progetto: adattare il `../` se
422
451
  // webpack.config.mjs NON è in una sottodirectory)
423
- // path.resolve(__dirname, '../templates/**/*.twig'),
424
- // path.resolve(__dirname, '../src/**/*.php'),
425
- path.resolve(__dirname, './index.js'), // entry js di default (vedi starter-install.sh)
426
- path.resolve(__dirname, './src/**/*.{js,mjs,jsx}'),
427
- path.resolve(__dirname, './src/**/*.ejs'), // template html di webpack
428
- path.resolve(__dirname, './error-pages/**/*.js'),
452
+ // path.resolve(__dirname, './templates/**/*.twig'),
453
+ // path.resolve(__dirname, './app/**/*.php'),
454
+ path.resolve(__dirname, './app/index.js'), // entry js di default (vedi starter-install.sh)
455
+ path.resolve(__dirname, './app/src/**/*.{js,mjs,jsx}'),
456
+ path.resolve(__dirname, './app/src/**/*.ejs'), // template html di webpack
457
+ path.resolve(__dirname, './app/error-pages/**/*.js'),
429
458
  // il js di minimo genera markup con classi proprie (snackbar, unsplash-page, ecc.)
430
459
  `${minimo_path}/src/**/*.{js,mjs}`,
431
460
  ],
@@ -462,14 +491,14 @@ const config = {
462
491
  // delle dipendenze (vedi webpack-config-modules/purgecss-variables-safelist.mjs)
463
492
  variablesSafelist: {
464
493
  declarationGlobs: [
465
- path.resolve(__dirname, './index.css'), // entry css di default (vedi starter-install.sh)
466
- path.resolve(__dirname, './index-critical.css'),
467
- path.resolve(__dirname, './src/**/*.css'),
468
- path.resolve(__dirname, './error-pages/**/*.css'),
494
+ path.resolve(__dirname, './app/index.css'), // entry css di default (vedi starter-install.sh)
495
+ path.resolve(__dirname, './app/index-critical.css'),
496
+ path.resolve(__dirname, './app/src/**/*.css'),
497
+ path.resolve(__dirname, './app/error-pages/**/*.css'),
469
498
  `${minimo_path}/src/**/*.css`,
470
499
  ],
471
500
  shadowGlobs: [
472
- path.resolve(__dirname, './src/web-components/**/*.css'),
501
+ path.resolve(__dirname, './app/src/web-components/**/*.css'),
473
502
  `${minimo_path}/src/web-components/**/*.css`,
474
503
  ],
475
504
  seeds: [
@@ -486,8 +515,15 @@ const config = {
486
515
  ], // end plugins
487
516
 
488
517
  module: {
518
+
489
519
  rules: [
490
520
 
521
+ // =>> icons.js è un barrel di puri re-export: nessun side effect
522
+ // {
523
+ // test: /[/\\]icons\.js$/,
524
+ // sideEffects: false
525
+ // },
526
+
491
527
  // =>> rules: js / jsx
492
528
  {
493
529
  test: /\.jsx?$/,
@@ -605,21 +641,21 @@ const config = {
605
641
  },
606
642
 
607
643
  // =>> Video
608
- {
609
- test: /\.(?:mp4|webm)$/i,
610
- // type: 'asset/resource',
611
- type: 'javascript/auto',
612
- use: [
613
- {
614
- loader: 'file-loader',
615
- options: {
616
- name: '[name].[contenthash][ext]',
617
- outputPath: 'video/',
618
- esModule: false,
619
- }
620
- }
621
- ]
622
- },
644
+ // {
645
+ // test: /\.(?:mp4|webm)$/i,
646
+ // // type: 'asset/resource',
647
+ // type: 'javascript/auto',
648
+ // use: [
649
+ // {
650
+ // loader: 'file-loader',
651
+ // options: {
652
+ // name: '[name].[contenthash][ext]',
653
+ // outputPath: 'video/',
654
+ // esModule: false,
655
+ // }
656
+ // }
657
+ // ]
658
+ // },
623
659
 
624
660
  // =>> rules: Fonts
625
661
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.32.0",
3
+ "version": "1.32.2",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -303,7 +303,50 @@ cols: [
303
303
  searchable, // false per escludere la colonna dalla ricerca globale
304
304
  hidden, // true per nascondere la colonna (esclusa anche dalla ricerca)
305
305
  sort, // 'asc' | 'desc' per ordinamento iniziale (solo su colonna singola)
306
- // ... tutte le altre opzioni columns di simple-datatables
306
+
307
+ format, // Formato datetime quando `type` è 'date' (default: 'YYYY-MM-DD')
308
+
309
+ render, // Callback (data, cell, rowIndex, cellIndex) => contenuto cella.
310
+ // È l'opzione nativa usata internamente per implementare i preset
311
+ // _renderMode e (indirettamente) _render/_renderTpl: se impostata
312
+ // esplicitamente dal consumer, i preset _renderMode vengono
313
+ // ignorati (vedi parseCols — la logica dei preset scatta solo se
314
+ // `render` non è già definita sulla colonna).
315
+
316
+ filter, // Array di valori (o predicati (value) => boolean) da usare per un
317
+ // filtro a tendina sulla colonna, in alternativa all'ordinamento.
318
+
319
+ headerClass, // Classi CSS per la cella <th> di intestazione.
320
+
321
+ cellClass, // Classi CSS per la cella <td> del corpo tabella.
322
+
323
+ numeric, // Default true. Se true, sequenze numeriche nelle stringhe sono
324
+ // trattate come un unico numero in ordinamento (es. "file 1.jpg"
325
+ // prima di "file 100.jpg").
326
+
327
+ caseFirst, // 'false' | 'upper' | 'lower' — ordine di maiuscole/minuscole
328
+ // nell'ordinamento stringa (default: 'false' = ordine del locale).
329
+
330
+ sortSequence, // Array di 'asc'/'desc' con cui alternare l'ordinamento ai click
331
+ // successivi sull'intestazione (ciascun valore ammesso una sola volta).
332
+
333
+ sensitivity, // 'base' | 'accent' | 'case' | 'variant' — sensibilità di
334
+ // ricerca/ordinamento a maiuscole e accenti (default: 'base').
335
+
336
+ ignorePunctuation, // Default true. Ignora la punteggiatura in ricerca/ordinamento.
337
+
338
+ searchItemSeparator, // Separatore usato per suddividere il contenuto della cella
339
+ // durante la ricerca (default: ' ').
340
+
341
+ searchMethod, // Funzione (query, cell, row, columnIndex, source) => boolean che
342
+ // sostituisce il metodo di ricerca predefinito sulla colonna.
343
+ // È l'opzione nativa usata internamente da _searchValue (vedi sopra):
344
+ // impostarla esplicitamente insieme a _searchValue sulla stessa
345
+ // colonna genera un conflitto (l'ultima assegnata sovrascrive l'altra).
346
+
347
+ locale, // Locale per l'ordinamento stringa, es. 'de-DE-u-co-phonebk'
348
+ // (default: 'en-US').
349
+
307
350
  }
308
351
  ]
309
352
  ```
@@ -40,8 +40,8 @@ export function parseCols(col_obj){
40
40
  ...col_obj,
41
41
  type: 'number',
42
42
  searchable: false,
43
- cellClass: 'text-end',
44
- headerClass: 'text-end',
43
+ cellClass: classnames('text-end', col_obj.cellClass),
44
+ headerClass: classnames('text-end', col_obj.headerClass),
45
45
  };
46
46
 
47
47
  } else if(col_obj._renderMode === 'email') {
@@ -59,7 +59,7 @@ export function parseCols(col_obj){
59
59
  ...col_obj,
60
60
  type: 'boolean',
61
61
  cellClass: styles.hasIcon,
62
- headerClass: 'text-center',
62
+ headerClass: classnames('text-center', col_obj.headerClass),
63
63
  render: (value, td) => {
64
64
 
65
65
  if(Boolean(value)) {
@@ -81,8 +81,8 @@ export function parseCols(col_obj){
81
81
  return {
82
82
  ...col_obj,
83
83
  type: 'string',
84
- cellClass: 'text-end',
85
- headerClass: 'text-end',
84
+ cellClass: classnames('text-end', col_obj.cellClass),
85
+ headerClass: classnames('text-end', col_obj.headerClass),
86
86
 
87
87
  render: (value, cell /*, dataIndex, rowIndex */) => { // value si riferisce al valore già trasformato nella pre-elaborazione dei dati
88
88
  /* {
@@ -119,15 +119,18 @@ export function parseCols(col_obj){
119
119
  }
120
120
  };
121
121
 
122
- } else if(col_obj._renderMode === 'numeric') {
123
- return {
124
- ...col_obj,
125
- // le classi definite dall'utente vengono unite, non sostituite
126
- cellClass: classnames('text-end text-numeric', col_obj.cellClass),
127
- headerClass: classnames('text-end text-numeric', col_obj.headerClass), // NB: usata anche per il footer
128
- };
122
+ } else if( col_obj._renderMode === 'numeric' ||
123
+ col_obj._renderMode === 'euro' ||
124
+ col_obj._renderMode === 'euro_currency' ||
125
+ col_obj._renderMode === 'euro_no_dec') {
126
+
127
+ const digits = col_obj._renderMode === 'numeric'
128
+ ? undefined
129
+ : col_obj._renderMode === 'euro_no_dec'
130
+ ? 0
131
+ : 2;
132
+
129
133
 
130
- } else if(col_obj._renderMode === 'euro_no_dec') {
131
134
  return {
132
135
  ...col_obj,
133
136
  render: (value, cell) => {
@@ -139,9 +142,11 @@ export function parseCols(col_obj){
139
142
  } else {
140
143
  cell.attributes['data-order'] = value;
141
144
  return Number(value).toLocaleString('it-IT', {
142
- minimumFractionDigits: 0,
143
- maximumFractionDigits: 0,
145
+ minimumFractionDigits: digits,
146
+ maximumFractionDigits: digits,
144
147
  useGrouping: 'always',
148
+ style: col_obj._renderMode === 'euro_currency' ? 'currency' : 'decimal',
149
+ currency: col_obj._renderMode === 'euro_currency' ? 'EUR' : undefined
145
150
  });
146
151
  }
147
152
  },