@massimo-cassandro/minimo 1.11.1 → 1.12.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/charts/src/node-helpers/create-svg-canvas-node.mjs +37 -0
- package/dev-tools/README.md +1 -1
- package/dev-tools/create-favicons/src/init-start-text.txt +20 -0
- package/dev-tools/update-version/index.mjs +1 -1
- package/dev-tools/update-version/src/chooser-inquirer.mjs +1 -1
- package/dev-tools/webpack-setup/starter-install.sh +149 -0
- package/dev-tools/webpack-setup/templates/__project__.code-workspace +93 -0
- package/dev-tools/webpack-setup/templates/_browserslistrc +27 -0
- package/dev-tools/webpack-setup/templates/_editorconfig +17 -0
- package/dev-tools/webpack-setup/templates/_gitignore +21 -0
- package/dev-tools/webpack-setup/templates/_prettierrc +9 -0
- package/dev-tools/webpack-setup/templates/eslint.config.mjs +31 -0
- package/dev-tools/webpack-setup/templates/jsconfig.json +22 -0
- package/dev-tools/webpack-setup/templates/package-tpl.json +37 -0
- package/dev-tools/webpack-setup/templates/stylelint.config.mjs +32 -0
- package/dev-tools/webpack-setup/webpack-modules/css-rules.mjs +177 -0
- package/dev-tools/webpack-setup/webpack-modules/get-jsConfig-aliases.mjs +33 -0
- package/dev-tools/webpack-setup/webpack-modules/mini-svg-data-uri-loader.cjs +25 -0
- package/dev-tools/webpack-setup/webpack-modules/postcss.config.mjs +77 -0
- package/dev-tools/webpack-setup/webpack-modules/svg-rules.mjs +154 -0
- package/dev-tools/webpack-setup/webpack-modules/svgo.config.mjs +26 -0
- package/dev-tools/webpack-setup/webpack-template.ejs +20 -0
- package/dev-tools/webpack-setup/webpack.config.mjs +585 -0
- package/package.json +5 -4
- package/snippets/ImgViewerController.php +403 -0
- package/snippets/UnsplashController.php +74 -0
- package/snippets/build-chrome-custom-device-list.mjs +101 -0
- package/snippets/config-templates/_env.local +13 -0
- package/snippets/config-templates/_github/dependabot.yml +10 -0
- package/snippets/config-templates/_hintrc.cjs +35 -0
- package/snippets/config-templates/_htaccess +69 -0
- package/snippets/config-templates/_npmignore +8 -0
- package/snippets/config-templates/_npmrc +1 -0
- package/snippets/config-templates/_stylelintignore +5 -0
- package/snippets/config-templates/babel.config--react.json +20 -0
- package/snippets/config-templates/babel.config--solidJS.json +8 -0
- package/snippets/config-templates/react/offcanvas/offcanvas.jsx +89 -0
- package/snippets/config-templates/react/offcanvas/offcanvas.module.scss +109 -0
- package/snippets/config-templates/robots.txt +5 -0
- package/snippets/config-templates/rollup.config.mjs +115 -0
- package/snippets/controllo-codice-fiscale-IT.js +48 -0
- package/snippets/controllo-partita-iva-IT.js +32 -0
- package/snippets/email-antispam.js +108 -0
- package/snippets/error-pages/bundles/TwigBundle/Exception/error.html.twig +33 -0
- package/snippets/error-pages/error-pages.js +37 -0
- package/snippets/festivita.js +101 -0
- package/snippets/minimo-form-layout.html.twig +446 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace App\Controller;
|
|
4
|
+
|
|
5
|
+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
6
|
+
use Symfony\Component\Routing\Annotation\Route;
|
|
7
|
+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
|
|
8
|
+
use Symfony\Component\HttpFoundation\Request;
|
|
9
|
+
use Symfony\Component\HttpFoundation\Response;
|
|
10
|
+
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
11
|
+
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ImgViewerController extends AbstractController
|
|
16
|
+
{
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param src: (string) path immagine
|
|
20
|
+
* @param raw: (bool) nessuna eleborazione (no image magick)
|
|
21
|
+
* @param crop: ritaglia l'immagine originale (prima dell'eventuale ridimensionamento con bb)
|
|
22
|
+
* secondo i parametri forniti: x,y (origine immagine), w,h (dimensioni ritaglio)
|
|
23
|
+
* es: crop=10,10,100,100 -> ritaglia un quadrato di 100px a partire dal punto 10,10
|
|
24
|
+
* @param bb: bounding box dell'area che deve contenere l'immagine ridimensionata
|
|
25
|
+
* @param fd: (bool) forza dimensioni (utilizzato in coppia con bb)
|
|
26
|
+
* @param q: compression quality
|
|
27
|
+
* @param alpha: mantiene la trasparenza nelle png (default 0)
|
|
28
|
+
* @param bg: in combinazione con alpha=1 definisce il bg color della png
|
|
29
|
+
* @param refresh: (bool) forza la rigenerazione dell'immagine
|
|
30
|
+
* @param f: definisce il formato dell'immagine, secondo le chiavi di ALLOWED_FORMATS
|
|
31
|
+
* il valore 'auto' (default) imposta il formato migliore secondo i valori in PREFERRED_AUTO_FORMATS
|
|
32
|
+
* @param ext: lascia inalterato il formato dell'immagine
|
|
33
|
+
* @param d: (bool) forza il download dell'immagine
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
// parametri get del viewer accettati
|
|
37
|
+
const ALLOWED_PARAMS = array('raw', 'bb', 'fd', 'q', 'alpha', 'bg', 'refresh', 'f', 'ext', 'd', 'crop');
|
|
38
|
+
// formati output
|
|
39
|
+
const ALLOWED_FORMATS = array(
|
|
40
|
+
'avif' => 'image/avif',
|
|
41
|
+
'pjpeg' => 'image/pjpeg',
|
|
42
|
+
'jpeg' => 'image/jpeg',
|
|
43
|
+
'jpg' => 'image/jpeg',
|
|
44
|
+
'png' => 'image/png',
|
|
45
|
+
'gif' => 'image/gif',
|
|
46
|
+
'webp' => 'image/webp',
|
|
47
|
+
'ico' => 'image/vnd.microsoft.icon'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// formati preferiti per la scelta automatica in ordine di preferenza
|
|
51
|
+
// in loro mancanza il formato prefefinito è jpeg
|
|
52
|
+
// (NB: devono essere uguali alle chiavi di ALLOWED_FORMATS)
|
|
53
|
+
const PREFERRED_AUTO_FORMATS = ['avif', 'webp'];
|
|
54
|
+
|
|
55
|
+
// formati input accettati da Imagick (in aggiunta a quelli definiti in ALLOWED_FORMATS)
|
|
56
|
+
const ALLOWED_INPUT = ['bmp', 'tiff', 'tif'];
|
|
57
|
+
|
|
58
|
+
// parametro compression quality di default
|
|
59
|
+
const DEFAULT_COMPRESSION_QUALITY = 60;
|
|
60
|
+
|
|
61
|
+
// src -> percorso assoluto dentro la dir public con gli slash
|
|
62
|
+
#[Route(path: '/iviewer', name: 'img_viewer')]
|
|
63
|
+
public function indexAction(Request $request)
|
|
64
|
+
{
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
$get = $request->query->all();
|
|
68
|
+
$src = $get['src'];
|
|
69
|
+
|
|
70
|
+
if (!$src)
|
|
71
|
+
throw $this->createNotFoundException('Parametro mancante! (src)');
|
|
72
|
+
|
|
73
|
+
// formati supportati dall'istanza imageMagick
|
|
74
|
+
$supported_formats = array_map("strtolower", \imagick::queryFormats());
|
|
75
|
+
|
|
76
|
+
// formati accettati dal browser
|
|
77
|
+
$accept = $request->server->get('HTTP_ACCEPT');
|
|
78
|
+
|
|
79
|
+
// format 'auto' default
|
|
80
|
+
if(!isset($get['f'])) $get['f'] = 'auto';
|
|
81
|
+
|
|
82
|
+
// format 'auto' -> sceglie il formato migliore per il browser, se disponibile
|
|
83
|
+
if(isset($get['f']) && strtolower($get['f']) == 'auto') {
|
|
84
|
+
|
|
85
|
+
foreach(self::PREFERRED_AUTO_FORMATS as $f) {
|
|
86
|
+
if(strpos($accept, self::ALLOWED_FORMATS[$f]) !== false &&
|
|
87
|
+
in_array($f, array_keys(self::ALLOWED_FORMATS)) &&
|
|
88
|
+
in_array($f, $supported_formats)
|
|
89
|
+
) {
|
|
90
|
+
$get['f']=$f;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
// durata della cache dei file: 7gg
|
|
98
|
+
$cache_lifetime = 604800;
|
|
99
|
+
|
|
100
|
+
$params = $this->cleanParams($get);
|
|
101
|
+
|
|
102
|
+
$cache_params_str = "";
|
|
103
|
+
|
|
104
|
+
// parte del nome file del cache formata da tutti i parametri concatenati tra loro
|
|
105
|
+
foreach ($params as $kg => $g) {
|
|
106
|
+
if ($kg != 'refresh' && $kg != 'raw')
|
|
107
|
+
$cache_params_str .= '_' . $kg . $g;
|
|
108
|
+
}
|
|
109
|
+
$cache_params_str = str_replace(',', '_', $cache_params_str);
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
$publicPath = $this->getParameter('kernel.project_dir') . '/public';
|
|
113
|
+
$filePath = $publicPath . $src;
|
|
114
|
+
|
|
115
|
+
$fileExt = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
|
|
116
|
+
// $fileBasename = strtolower(pathinfo($filePath, PATHINFO_BASENAME));
|
|
117
|
+
// $fileCacheName = $fileBasename; // porzione inziale del nome del file di cache
|
|
118
|
+
$fileCacheName = str_replace('/', '_', $src); // porzione inziale del nome del file di cache
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if (isset($params['d'])) {
|
|
122
|
+
$disposition = 'attachment';
|
|
123
|
+
} else {
|
|
124
|
+
$disposition = 'inline';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
// elaborazione immagine: se sono presenti parametri, non è settato raw ed è un formato trattabile da imagick
|
|
129
|
+
if (count($params) && !isset($params['raw']) && in_array($fileExt, array_merge(self::ALLOWED_INPUT, array_keys(self::ALLOWED_FORMATS)))) {
|
|
130
|
+
|
|
131
|
+
// se è richiesto un formato deve essere tra quelli permessi
|
|
132
|
+
if (isset($params['f']) &&
|
|
133
|
+
in_array($params['f'], array_keys(self::ALLOWED_FORMATS)) &&
|
|
134
|
+
in_array($params['f'], $supported_formats)
|
|
135
|
+
) {
|
|
136
|
+
|
|
137
|
+
$format = $params['f'];
|
|
138
|
+
|
|
139
|
+
// se è presente il parametro ext ed è tra quelli permessi
|
|
140
|
+
} else if (isset($params['ext']) && $params['ext'] && in_array(strtolower($fileExt), array_keys(self::ALLOWED_FORMATS))) {
|
|
141
|
+
|
|
142
|
+
$format = strtolower($fileExt);
|
|
143
|
+
|
|
144
|
+
// formato predefinito in assenza di altre impostazioni
|
|
145
|
+
} else {
|
|
146
|
+
$format = 'jpeg';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
$fileCacheName = $fileCacheName . $cache_params_str . '.' . ($format == 'pjpeg' ? 'jpeg' : $format);
|
|
150
|
+
|
|
151
|
+
$cachefile = $this->getParameter('cache_dir') . $fileCacheName;
|
|
152
|
+
|
|
153
|
+
// definizione della qualità della compressione dell'immagine
|
|
154
|
+
$compressionQuality = !empty($params['q']) ? intval($params['q']) : self::DEFAULT_COMPRESSION_QUALITY;
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
// elaborazione con imagick per i seguenti casi:
|
|
158
|
+
// 1) non esiste il file nella cartella cache
|
|
159
|
+
// 2) la cache è scaduta
|
|
160
|
+
// 3) è richiesto il refresh
|
|
161
|
+
if (!file_exists($cachefile) || (filemtime($cachefile) + $cache_lifetime) < time() || isset($params['refresh'])) {
|
|
162
|
+
|
|
163
|
+
// inizializzazione imagick
|
|
164
|
+
$img = new \Imagick();
|
|
165
|
+
$img->readImage($filePath);
|
|
166
|
+
|
|
167
|
+
$img->stripImage(); // Strips an image of all profiles and comments
|
|
168
|
+
|
|
169
|
+
if(isset($params['crop']) or isset($params['bb'])) {
|
|
170
|
+
// dimensioni originali
|
|
171
|
+
$ow = $img->getImageWidth();
|
|
172
|
+
$oh = $img->getImageHeight();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if(isset($params['crop'])) {
|
|
177
|
+
$crop_params = array_map( fn($val) => intval(trim($val)), explode(',', $params['crop']));
|
|
178
|
+
|
|
179
|
+
// devono essere presenti tutti e 4 i parametri e devono essere maggiori di zero
|
|
180
|
+
if(count($crop_params) != 4 or min($crop_params) < 0) {
|
|
181
|
+
throw $this->createNotFoundException('Errore di configurazione! (crop 1)');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
[$x,$y,$crop_w,$crop_h] = $crop_params;
|
|
185
|
+
|
|
186
|
+
// l'area ritagliata non può essere più grande dell'immagine
|
|
187
|
+
if($x + $crop_w > $ow or $y + $crop_h > $oh) {
|
|
188
|
+
throw $this->createNotFoundException('Errore di configurazione! (crop 2)');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
$img->cropImage($crop_w, $crop_h, $x, $y);
|
|
192
|
+
|
|
193
|
+
// nuove dimensioni dell'immagine (corrispondono a $crop_w e $crop_h)
|
|
194
|
+
$ow = $img->getImageWidth();
|
|
195
|
+
$oh = $img->getImageHeight();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (isset($params['bb'])) {
|
|
199
|
+
$bb_param = strtolower($params['bb']);
|
|
200
|
+
$bb_has_x = strpos($bb_param, 'x') !== false;
|
|
201
|
+
|
|
202
|
+
if ($bb_has_x) {
|
|
203
|
+
// dimensioni richieste
|
|
204
|
+
// se un parametro è mancante viene impostato a 0 e non ha influenza nelle elaborazioni successive
|
|
205
|
+
[$w, $h] = array_map( fn($val) => $val? (int)$val : 0, explode('x', $bb_param));
|
|
206
|
+
|
|
207
|
+
// le dimensioni richieste non possono superare quelle originali
|
|
208
|
+
if ($w > $ow) $w = $ow;
|
|
209
|
+
if ($h > $oh) $h = $oh;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// fd => l'immagine deve rispettare con precisione le dimensioni richieste
|
|
214
|
+
// è necessario che siano presenti entrambi i parametri bb
|
|
215
|
+
if (isset($params['bb']) && isset($params['fd']) && $bb_has_x && $w > 0 && $h > 0) {
|
|
216
|
+
|
|
217
|
+
if ($ow < $w && $oh < $h) {
|
|
218
|
+
$nb = $ow;
|
|
219
|
+
$nh = $oh;
|
|
220
|
+
|
|
221
|
+
if ($w > $h) {
|
|
222
|
+
$r = $h / $w;
|
|
223
|
+
} else {
|
|
224
|
+
$r = $w / $h;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if ($nb > $nh) {
|
|
228
|
+
$nh = $r * $nb;
|
|
229
|
+
} else {
|
|
230
|
+
$nb = $r * $nh;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
$w = $nb;
|
|
234
|
+
$h = $nh;
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
$img->cropThumbnailImage($w, $h);
|
|
239
|
+
// $img->resizeImage($w, $h, \imagick::FILTER_GAUSSIAN, 0);
|
|
240
|
+
|
|
241
|
+
} elseif (isset($params['bb']) && $bb_has_x) {
|
|
242
|
+
|
|
243
|
+
if ($w != 0 || $h != 0) {
|
|
244
|
+
$nb = $ow;
|
|
245
|
+
$nh = $oh;
|
|
246
|
+
if ($w != 0 && $w < $nb) {
|
|
247
|
+
$nh = ($w / $nb) * $nh;
|
|
248
|
+
$nb = $w;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if ($h != 0 && $h < $nh) {
|
|
252
|
+
$nb = ($h / $nh) * $nb;
|
|
253
|
+
$nh = $h;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
$w = $nb;
|
|
257
|
+
$h = $nh;
|
|
258
|
+
}
|
|
259
|
+
$img->thumbnailImage($w, $h, true);
|
|
260
|
+
// $img->resizeImage($w, $h, \imagick::FILTER_GAUSSIAN, 0);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// compressione immagine
|
|
264
|
+
if ($compressionQuality) {
|
|
265
|
+
$img->setImageCompressionQuality($compressionQuality);
|
|
266
|
+
}
|
|
267
|
+
//$img->setImageAlphaChannel(\imagick::COMPOSITE_CLEAR);
|
|
268
|
+
//$img->setBackgroundColor(new \ImagickPixel('white'));
|
|
269
|
+
|
|
270
|
+
// formato immagine
|
|
271
|
+
|
|
272
|
+
$img->setImageFormat($format);
|
|
273
|
+
|
|
274
|
+
// $mimeType = $img->getImageMimeType();
|
|
275
|
+
$mimeType = self::ALLOWED_FORMATS[$format];
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
/*if ($format == 'webp') {
|
|
279
|
+
// per i webp non posso recuperare direttamente il mime type con il metodo
|
|
280
|
+
$mimeType = 'image/webp';
|
|
281
|
+
|
|
282
|
+
//$img->setImageAlphaChannel(\imagick::COMPOSITE_CLEAR);
|
|
283
|
+
//$img->setBackgroundColor(new \ImagickPixel('transparent'));
|
|
284
|
+
|
|
285
|
+
} else if ($format == 'pjpeg') {
|
|
286
|
+
$mimeType = 'image/jpeg';
|
|
287
|
+
|
|
288
|
+
} else */
|
|
289
|
+
|
|
290
|
+
if ($format == 'ico') {
|
|
291
|
+
$img->setImageAlphaChannel(\imagick::COMPOSITE_CLEAR);
|
|
292
|
+
$img->setBackgroundColor(new \ImagickPixel('transparent'));
|
|
293
|
+
$img->cropThumbnailImage(16, 16);
|
|
294
|
+
// $mimeType = self::ALLOWED_FORMATS['ico']; //'image/vnd.microsoft.icon';
|
|
295
|
+
|
|
296
|
+
} else if ($format == 'png') {
|
|
297
|
+
$mimeType = 'png';
|
|
298
|
+
if (isset($params['alpha']) && isset($params['bg']) && preg_match('/[0-9a-f]{6}/i', $params['bg'])) {
|
|
299
|
+
$bgColor = '#' . $params['bg'];
|
|
300
|
+
// elimino la trasparenza
|
|
301
|
+
//$img->setImageAlphaChannel(\imagick::COMPOSITE_CLEAR);
|
|
302
|
+
$img->setImageBackgroundColor($bgColor);
|
|
303
|
+
$img = $img->flattenImages();
|
|
304
|
+
|
|
305
|
+
} else {
|
|
306
|
+
//$bgColor = '#ffffff';
|
|
307
|
+
//$img->setImageAlphaChannel(\imagick::COMPOSITE_CLEAR);
|
|
308
|
+
//$img->setBackgroundColor(new \ImagickPixel('transparent'));
|
|
309
|
+
|
|
310
|
+
$draw = new \ImagickDraw();
|
|
311
|
+
$draw->setStrokeAntialias(false);
|
|
312
|
+
$img->drawImage($draw);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
$img->writeImage($cachefile);
|
|
317
|
+
$img->clear();
|
|
318
|
+
$img->destroy();
|
|
319
|
+
|
|
320
|
+
} else {
|
|
321
|
+
|
|
322
|
+
$mimeType = self::ALLOWED_FORMATS[$format];
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
// nessuna elaborazione richiesta: restituisce il file originale
|
|
328
|
+
} else {
|
|
329
|
+
|
|
330
|
+
$cachefile = $filePath;
|
|
331
|
+
// $fileCacheName = $fileBasename . '.' . $fileExt;
|
|
332
|
+
$fileCacheName = str_replace('/', '_', $src);
|
|
333
|
+
|
|
334
|
+
if ($fileExt == 'svg')
|
|
335
|
+
$mimeType = 'image/svg+xml';
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
$response = new BinaryFileResponse($cachefile);
|
|
340
|
+
$response->trustXSendfileTypeHeader();
|
|
341
|
+
|
|
342
|
+
if (isset($mimeType)) {
|
|
343
|
+
$response->headers->set('Content-Type', $mimeType);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
$response->headers->set('Content-Disposition', $disposition . '; filename = ' . $fileCacheName);
|
|
347
|
+
|
|
348
|
+
return $response;
|
|
349
|
+
|
|
350
|
+
//return array();
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
protected function cleanParams($params) {
|
|
355
|
+
|
|
356
|
+
//compatibilità con vecchio parametro jq
|
|
357
|
+
// if(isset($params['jq']) && !isset($params['q'])) {
|
|
358
|
+
// $params['q'] = $params['jq'];
|
|
359
|
+
// }
|
|
360
|
+
|
|
361
|
+
// array_walk($params, create_function('&$val', '$val = trim($val);'));
|
|
362
|
+
// array_walk($params, function ($val): string {
|
|
363
|
+
// return trim($val);
|
|
364
|
+
// });
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
foreach ($params as $key => $value) {
|
|
368
|
+
if(!in_array($key, self::ALLOWED_PARAMS)) {
|
|
369
|
+
unset($params[$key]);
|
|
370
|
+
} else if($value) {
|
|
371
|
+
$params[$key] = trim($value);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if(isset($params['f'])) {
|
|
376
|
+
$params['f'] = strtolower($params['f']);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return $params;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// restituisce un json con le info dell'immagine indicata
|
|
383
|
+
#[Route(path: '/iviewer-info', name: 'img_viewer_info')]
|
|
384
|
+
public function iviewerInfo(Request $request)
|
|
385
|
+
{
|
|
386
|
+
$get = $request->query->all();
|
|
387
|
+
$src = $get['src'];
|
|
388
|
+
|
|
389
|
+
if (!$src)
|
|
390
|
+
throw $this->createNotFoundException('iviewer-info: Parametro mancante! (src)');
|
|
391
|
+
|
|
392
|
+
$publicPath = $this->getParameter('kernel.project_dir') . '/public';
|
|
393
|
+
$filePath = $publicPath . $src;
|
|
394
|
+
|
|
395
|
+
$img_info = getimagesize($filePath);
|
|
396
|
+
|
|
397
|
+
$response = new JsonResponse();
|
|
398
|
+
$response->setData($img_info);
|
|
399
|
+
|
|
400
|
+
return $response;
|
|
401
|
+
|
|
402
|
+
}
|
|
403
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace App\Controller;
|
|
4
|
+
|
|
5
|
+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
6
|
+
use Symfony\Component\Routing\Annotation\Route;
|
|
7
|
+
use Symfony\Component\HttpFoundation\Request;
|
|
8
|
+
use Symfony\Component\HttpFoundation\Response;
|
|
9
|
+
|
|
10
|
+
class UnsplashController extends AbstractController
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
#[Route('/get-unsplash', name: 'get_unsplash')]
|
|
14
|
+
public function get(Request $request)
|
|
15
|
+
{
|
|
16
|
+
// $get = $request->query->all();
|
|
17
|
+
// $src = $get['src'];
|
|
18
|
+
$orientation = $request->query->get('orientation', 'landscape'); // landscape, portrait, squarish, null
|
|
19
|
+
|
|
20
|
+
$allowed = ['landscape', 'portrait', 'squarish', null];
|
|
21
|
+
if (!in_array($orientation, $allowed)) {
|
|
22
|
+
$orientation = 'landscape';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
$unsplash_access_key = 'xxxxxxx';
|
|
26
|
+
$collections_ids = '3660951'; // comma separated list
|
|
27
|
+
$count = null;
|
|
28
|
+
|
|
29
|
+
$url = 'https://api.unsplash.com/photos/random' .
|
|
30
|
+
"?client_id={$unsplash_access_key}" .
|
|
31
|
+
"&collections={$collections_ids}" .
|
|
32
|
+
($orientation? "&orientation={$orientation}" : '') .
|
|
33
|
+
($count != null? "&count={$count}" : '');
|
|
34
|
+
|
|
35
|
+
$json = file_get_contents($url);
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
$response = new Response();
|
|
39
|
+
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
|
|
40
|
+
$response->setContent($json);
|
|
41
|
+
|
|
42
|
+
$env = $this->getParameter('kernel.environment');
|
|
43
|
+
|
|
44
|
+
return $response;
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[Route('/unsplash-browser', name: 'unsplash_browser')]
|
|
49
|
+
public function browse(Request $request)
|
|
50
|
+
{
|
|
51
|
+
$unsplash_access_key = 'xxxxxxx';
|
|
52
|
+
|
|
53
|
+
$get = $request->query->all();
|
|
54
|
+
|
|
55
|
+
$url = 'https://api.unsplash.com/search/photos' .
|
|
56
|
+
"?client_id={$unsplash_access_key}";
|
|
57
|
+
|
|
58
|
+
foreach($get as $key => $value) {
|
|
59
|
+
$url .= '&' . rawurlencode($key) . '=' . rawurlencode($value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$json = file_get_contents($url);
|
|
63
|
+
|
|
64
|
+
$response = new Response();
|
|
65
|
+
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
|
|
66
|
+
$response->setContent($json);
|
|
67
|
+
|
|
68
|
+
$env = $this->getParameter('kernel.environment');
|
|
69
|
+
|
|
70
|
+
return $response;
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-env node */
|
|
3
|
+
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
|
|
6
|
+
const device_std_height = 700,
|
|
7
|
+
|
|
8
|
+
breakpoints = [
|
|
9
|
+
{title: 'moto g5', w: 360, h: 512},
|
|
10
|
+
|
|
11
|
+
{title: 'bs5 xs max', w: 575, h: device_std_height},
|
|
12
|
+
{title: 'bs5 sm min', w: 576, h: device_std_height},
|
|
13
|
+
{title: 'bs5 sm max', w: 767, h: device_std_height},
|
|
14
|
+
{title: 'bs5 md min', w: 768, h: device_std_height},
|
|
15
|
+
{title: 'bs5 md max', w: 991, h: device_std_height},
|
|
16
|
+
{title: 'bs5 lg min', w: 992, h: device_std_height},
|
|
17
|
+
{title: 'bs5 lg max', w: 1199, h: device_std_height},
|
|
18
|
+
{title: 'bs5 xl min', w: 1200, h: device_std_height},
|
|
19
|
+
{title: 'bs5 xl max', w: 1399, h: device_std_height},
|
|
20
|
+
{title: 'bs5 xxl min', w: 1400, h: device_std_height},
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
{title: 'schermo staff BV (1280x960)', w: 1280, h: 960},
|
|
24
|
+
{title: '1366x768', w: 1366, h: 768},
|
|
25
|
+
{title: '1280x720 (HD)', w: 1280, h: 720},
|
|
26
|
+
{title: '1920x1080 (full HD)', w: 1920, h: 1980},
|
|
27
|
+
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
let device_list = breakpoints.map((item, idx) => {
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
'title': ('00' + String(idx+1)).slice(-2) + '. ' + item.title,
|
|
34
|
+
'type': 'unknown',
|
|
35
|
+
'user-agent': '',
|
|
36
|
+
'capabilities': [
|
|
37
|
+
'mobile'
|
|
38
|
+
],
|
|
39
|
+
'screen': {
|
|
40
|
+
'device-pixel-ratio': 0,
|
|
41
|
+
'vertical': {
|
|
42
|
+
'width': item.w,
|
|
43
|
+
'height': item.h
|
|
44
|
+
},
|
|
45
|
+
'horizontal': {
|
|
46
|
+
'width': item.h,
|
|
47
|
+
'height': item.w
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
'modes': [
|
|
51
|
+
{
|
|
52
|
+
'title': '',
|
|
53
|
+
'orientation': 'vertical',
|
|
54
|
+
'insets': {
|
|
55
|
+
'left': 0,
|
|
56
|
+
'top': 0,
|
|
57
|
+
'right': 0,
|
|
58
|
+
'bottom': 0
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
'title': '',
|
|
63
|
+
'orientation': 'horizontal',
|
|
64
|
+
'insets': {
|
|
65
|
+
'left': 0,
|
|
66
|
+
'top': 0,
|
|
67
|
+
'right': 0,
|
|
68
|
+
'bottom': 0
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
'show-by-default': true,
|
|
73
|
+
'dual-screen': false,
|
|
74
|
+
'show': 'Default',
|
|
75
|
+
'user-agent-metadata': {
|
|
76
|
+
'brands': [
|
|
77
|
+
{
|
|
78
|
+
'brand': '',
|
|
79
|
+
'version': ''
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
'fullVersion': '',
|
|
83
|
+
'platform': '',
|
|
84
|
+
'platformVersion': '',
|
|
85
|
+
'architecture': '',
|
|
86
|
+
'model': '',
|
|
87
|
+
'mobile': true
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
const dest = 'ChromeCustomDeviceList.txt',
|
|
94
|
+
str = '"custom-emulated-device-list":"'+ JSON.stringify(device_list).replace(/"/g, '\\"') + '",';
|
|
95
|
+
|
|
96
|
+
fs.writeFileSync(dest, str);
|
|
97
|
+
|
|
98
|
+
console.log (
|
|
99
|
+
'copiare all\'interno del file `~/Library/Application Support/Google/Chrome/Default/Preferences` (NB: è un file JSON)\n'+
|
|
100
|
+
'vedi: https://stackoverflow.com/a/70905335/743443\n'
|
|
101
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
DATABASE_URL=mysql://root:mysql8root@127.0.0.1:3306/xxxx?serverVersion=8.0
|
|
2
|
+
|
|
3
|
+
APP_ENV=dev
|
|
4
|
+
APP_DEBUG=1
|
|
5
|
+
|
|
6
|
+
### mailHog
|
|
7
|
+
MAILER_DSN=smtp://localhost:1025
|
|
8
|
+
|
|
9
|
+
### supporto webpack
|
|
10
|
+
# cartella, dentro public, in cui webpack salva js, css immagini ecc
|
|
11
|
+
ASSETS_DIR=_dev
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "npm" # Indica che stiamo usando NPM
|
|
4
|
+
directory: "/" # Dove si trova il package.json
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "monthly" # Può essere: daily, weekly, monthly
|
|
7
|
+
open-pull-requests-limit: 15 # Massimo 10 PR aperte contemporaneamente
|
|
8
|
+
labels:
|
|
9
|
+
- "dependencies"
|
|
10
|
+
- "javascript"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
"connector": {
|
|
3
|
+
"name": "local",
|
|
4
|
+
"options": {
|
|
5
|
+
"pattern": ["./build/**/*.html"] // Analizza i file HTML generati nella directory di build
|
|
6
|
+
}
|
|
7
|
+
},
|
|
8
|
+
"extends": [
|
|
9
|
+
"development", // Configurazione base per lo sviluppo
|
|
10
|
+
"accessibility", // Regole per l'accessibilità
|
|
11
|
+
"performance", // Regole per le prestazioni
|
|
12
|
+
"security", // Regole per la sicurezza
|
|
13
|
+
"html-checker" // Controllo della validità HTML
|
|
14
|
+
],
|
|
15
|
+
"hints": {
|
|
16
|
+
"axe": "error", // Controlla l'accessibilità con axe-core
|
|
17
|
+
"content-type": "error", // Verifica i tipi di contenuto corretti
|
|
18
|
+
"disown-opener": "warning", // Consiglia di usare `rel="noopener"`
|
|
19
|
+
"http-cache": ["warning", { "maxAge": 31536000 }], // Suggerisce una cache HTTP ottimale
|
|
20
|
+
"image-optimization-cloudinary": "off", // Disattiva l'ottimizzazione delle immagini
|
|
21
|
+
"meta-viewport": "error", // Verifica la presenza del meta tag viewport
|
|
22
|
+
"no-vulnerable-javascript-libraries": "error", // Controlla librerie JS vulnerabili
|
|
23
|
+
"performance-budget": [
|
|
24
|
+
"warning",
|
|
25
|
+
{
|
|
26
|
+
"resourceTypes": {
|
|
27
|
+
"script": 250, // Limite di 250 KB per gli script
|
|
28
|
+
"image": 500 // Limite di 500 KB per le immagini
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"strict-transport-security": "error", // Suggerisce l'uso di HSTS
|
|
33
|
+
"validate-set-cookie-header": "error" // Controlla l'uso corretto dell'header Set-Cookie
|
|
34
|
+
}
|
|
35
|
+
};
|