@lad-sapienza/scms-core 0.1.0-alpha.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -4
- package/bin/add-collection.mjs +37 -6
- package/bin/add-content.mjs +88 -13
- package/bin/create.mjs +1 -1
- package/bin/lib/optimize-images.mjs +440 -0
- package/bin/optimize-images.mjs +95 -0
- package/components/Map/Map.tsx +44 -3
- package/components/Map/MapMdx.tsx +2 -0
- package/components/Map/README.md +63 -1
- package/components/Map/index.ts +0 -1
- package/components/Map/types.ts +30 -0
- package/components/Map/utils.ts +19 -1
- package/components/Record/RecordFetcher.tsx +1 -1
- package/components/Record/useRecordFetcher.ts +1 -1
- package/components/i18n/builtinDictionary.ts +1 -0
- package/index.ts +1 -1
- package/package.json +27 -4
- package/scms.ts +69 -17
- package/template/README.md.tmpl +13 -0
- package/template/package.json.tmpl +2 -1
package/components/Map/README.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# Map Component
|
|
2
2
|
|
|
3
|
-
Interactive map built on [MapLibre GL JS](https://maplibre.org/) (via
|
|
3
|
+
Interactive map built on [MapLibre GL JS](https://maplibre.org/) **v6** (via
|
|
4
4
|
`@vis.gl/react-maplibre`). Renders a raster basemap, any number of toggleable
|
|
5
5
|
overlay layers pulled from heterogeneous data sources (GeoJSON, CSV, JSON,
|
|
6
6
|
Directus, a generic API, or raster XYZ/WMS tiles), and a built-in layer
|
|
7
7
|
control for switching basemaps and toggling overlays.
|
|
8
8
|
|
|
9
|
+
MapLibre v6 requires **WebGL2** (universally supported by current browsers) and
|
|
10
|
+
no longer auto-loads its Web Worker — `Map.tsx` wires the worker up itself with
|
|
11
|
+
a Vite `?worker&url` import, so consuming sites need no bundler/worker config.
|
|
12
|
+
The `maplibre-gl` peer dependency is `^6`.
|
|
13
|
+
|
|
9
14
|
## Basic usage
|
|
10
15
|
|
|
11
16
|
```mdx
|
|
@@ -26,6 +31,30 @@ touching `overlayLayers` directly:
|
|
|
26
31
|
<Map directus={{ table: 'sites', geoField: 'location' }} />
|
|
27
32
|
```
|
|
28
33
|
|
|
34
|
+
For one or a few hand-placed points (e.g. the location of a single site) use
|
|
35
|
+
`markers` — no data file needed. The map fits to them automatically; a lone
|
|
36
|
+
marker is centred at a regional zoom (≥ 12) rather than zoomed to the max:
|
|
37
|
+
|
|
38
|
+
```mdx
|
|
39
|
+
<Map markers={{ lng: 12.4964, lat: 41.9028, label: 'Roma' }} />
|
|
40
|
+
|
|
41
|
+
<Map markers={[
|
|
42
|
+
{ lng: 12.49, lat: 41.90, label: 'Site A' },
|
|
43
|
+
{ lng: 12.51, lat: 41.88, label: 'Site B' },
|
|
44
|
+
]} />
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`label` is optional (shown in a popup as plain text). Markers are an extra
|
|
48
|
+
overlay layer and combine with any of the shorthands below.
|
|
49
|
+
|
|
50
|
+
`markersZoom` fixes the zoom: the map is centred on the markers at that level
|
|
51
|
+
instead of being fitted to their extent — useful to give a single site the
|
|
52
|
+
same geographic context on every page:
|
|
53
|
+
|
|
54
|
+
```mdx
|
|
55
|
+
<Map markers={{ lng: 12.4964, lat: 41.9028, label: 'Roma' }} markersZoom={9} />
|
|
56
|
+
```
|
|
57
|
+
|
|
29
58
|
`geojson`/`csv`/`json`/`directus` each accept either a bare string (path/URL)
|
|
30
59
|
or an object with `name`, `style`, `popup`, `fitToContent`, `filter` — see
|
|
31
60
|
`MapProps` in [`types.ts`](./types.ts) for the exact shape of each.
|
|
@@ -148,6 +177,32 @@ add `popupTemplate`/`fitToContent`/`visible` (properties the style spec
|
|
|
148
177
|
itself has no room for). See `MapProps` in [`types.ts`](./types.ts) for the
|
|
149
178
|
exact shape.
|
|
150
179
|
|
|
180
|
+
## Styles (MapLibre CSS)
|
|
181
|
+
|
|
182
|
+
`Map.tsx` imports `maplibre-gl/dist/maplibre-gl.css` itself, so you do not need
|
|
183
|
+
to import it yourself: it styles the layer control, zoom/compass buttons,
|
|
184
|
+
attribution and popups. Without it the map still renders, but those controls
|
|
185
|
+
and popups appear unstyled.
|
|
186
|
+
|
|
187
|
+
That import is not always linked from the page in production builds (`astro
|
|
188
|
+
dev` is unaffected). It is missed when `<Map>` is imported from an MDX
|
|
189
|
+
content-collection entry whose `render()`ed `Content` is passed as a prop to
|
|
190
|
+
another component (e.g. `<ArticlePage Content={Content} />`): Astro emits the
|
|
191
|
+
CSS file but no page links it. This happens with every client directive
|
|
192
|
+
(`client:load` and `client:only="react"` alike).
|
|
193
|
+
|
|
194
|
+
`scms()` works around this by linking the stylesheet from every page. If you
|
|
195
|
+
are on a version that predates that fix, or you set `scms({ mapCss: false })`
|
|
196
|
+
(e.g. because the site has no maps, or to avoid the stylesheet on pages
|
|
197
|
+
without one), import it once in your layout instead:
|
|
198
|
+
|
|
199
|
+
```astro
|
|
200
|
+
---
|
|
201
|
+
// src/layouts/BaseLayout.astro
|
|
202
|
+
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
203
|
+
---
|
|
204
|
+
```
|
|
205
|
+
|
|
151
206
|
## Props
|
|
152
207
|
|
|
153
208
|
### `Map`
|
|
@@ -199,3 +254,10 @@ exact shape.
|
|
|
199
254
|
only two functions that build tile URL templates — both `baseLayers` and
|
|
200
255
|
raster `overlayLayers` go through them, so there's one place to fix or
|
|
201
256
|
extend tile-URL construction.
|
|
257
|
+
- MapLibre GL JS v6 dropped the automatic worker bootstrap, so `Map.tsx`
|
|
258
|
+
imports `maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url` and calls
|
|
259
|
+
`setWorkerUrl()` at module load, before `@vis.gl/react-maplibre` constructs
|
|
260
|
+
any map. `?worker&url` (not `?url`) routes the worker through Vite's worker
|
|
261
|
+
pipeline so its `maplibre-gl-shared.mjs` sibling is bundled in. `scms.ts`
|
|
262
|
+
adds `ssr.noExternal: ['maplibre-gl']` so that import also resolves in the
|
|
263
|
+
SSR pass for consumers rendering `<Map client:load>`.
|
package/components/Map/index.ts
CHANGED
package/components/Map/types.ts
CHANGED
|
@@ -124,6 +124,12 @@ export interface OverlayLayerConfig {
|
|
|
124
124
|
/** Fit map bounds to layer content */
|
|
125
125
|
fitToContent?: boolean;
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* With `fitToContent`: centre on the content's bounds at this fixed zoom
|
|
129
|
+
* instead of fitting them (used by the `markers` shorthand).
|
|
130
|
+
*/
|
|
131
|
+
fitZoom?: number;
|
|
132
|
+
|
|
127
133
|
/** Optional client-side filter for features */
|
|
128
134
|
filter?: FilterObject | ((feature: any) => boolean);
|
|
129
135
|
|
|
@@ -131,6 +137,17 @@ export interface OverlayLayerConfig {
|
|
|
131
137
|
searchInFields?: SearchInFields;
|
|
132
138
|
}
|
|
133
139
|
|
|
140
|
+
/**
|
|
141
|
+
* A single point marker for the `markers` shorthand — for maps with one or a
|
|
142
|
+
* few hand-placed points, no data file needed.
|
|
143
|
+
*/
|
|
144
|
+
export interface MarkerConfig {
|
|
145
|
+
lng: number;
|
|
146
|
+
lat: number;
|
|
147
|
+
/** Text shown in the popup on hover/click (plain text, HTML-escaped) */
|
|
148
|
+
label?: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
134
151
|
export interface MapProps {
|
|
135
152
|
/** Map height (CSS string) */
|
|
136
153
|
height?: string;
|
|
@@ -197,6 +214,19 @@ export interface MapProps {
|
|
|
197
214
|
filter?: FilterObject | ((row: any) => boolean);
|
|
198
215
|
};
|
|
199
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Inline markers - one or a few hand-placed points, e.g. to give the
|
|
219
|
+
* geographic context of a single site. Rendered as an extra overlay layer
|
|
220
|
+
* and, by default, the map is fitted to them.
|
|
221
|
+
*/
|
|
222
|
+
markers?: MarkerConfig | MarkerConfig[];
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Fixed zoom for the `markers`: the map is centred on them at this zoom
|
|
226
|
+
* instead of being fitted to their extent. Handy for a single site.
|
|
227
|
+
*/
|
|
228
|
+
markersZoom?: number;
|
|
229
|
+
|
|
200
230
|
/** JSON shorthand - for simple single-layer maps */
|
|
201
231
|
json?: any[] | string;
|
|
202
232
|
|
package/components/Map/utils.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { DataRow } from '../../utils/data-fetcher';
|
|
6
6
|
import type { FeatureCollection, Feature, Geometry } from 'geojson';
|
|
7
|
-
import type { WmsSourceConfig } from './types';
|
|
7
|
+
import type { WmsSourceConfig, MarkerConfig } from './types';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Tries to identify latitude and longitude fields from a data row
|
|
@@ -117,6 +117,24 @@ export function dataToGeoJson(
|
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Converts the `markers` shorthand to a GeoJSON FeatureCollection of points,
|
|
122
|
+
* dropping entries whose coordinates aren't finite numbers. The label ends up
|
|
123
|
+
* in the `label` property, which the markers layer's popup template reads.
|
|
124
|
+
*/
|
|
125
|
+
export function markersToGeoJson(markers: MarkerConfig | MarkerConfig[]): FeatureCollection {
|
|
126
|
+
const list = Array.isArray(markers) ? markers : [markers];
|
|
127
|
+
const features: Feature[] = list
|
|
128
|
+
.filter(m => m && m.lng != null && m.lat != null
|
|
129
|
+
&& Number.isFinite(Number(m.lng)) && Number.isFinite(Number(m.lat)))
|
|
130
|
+
.map(m => ({
|
|
131
|
+
type: 'Feature',
|
|
132
|
+
geometry: { type: 'Point', coordinates: [Number(m.lng), Number(m.lat)] },
|
|
133
|
+
properties: { label: m.label ?? '' }
|
|
134
|
+
}));
|
|
135
|
+
return { type: 'FeatureCollection', features };
|
|
136
|
+
}
|
|
137
|
+
|
|
120
138
|
/**
|
|
121
139
|
* Expands an XYZ tile URL template's {s} subdomain placeholder into the
|
|
122
140
|
* standard a/b/c rotation (as Leaflet does natively). Returns the url
|
|
@@ -49,7 +49,7 @@ function DefaultError({ table, id }: { table: string; id: string }) {
|
|
|
49
49
|
* **Usage in an Astro page:**
|
|
50
50
|
* ```astro
|
|
51
51
|
* ---
|
|
52
|
-
* import RecordFetcher from '@lad-sapienza/scms-core/components/Record
|
|
52
|
+
* import { RecordFetcher } from '@lad-sapienza/scms-core/components/Record';
|
|
53
53
|
* import MyLayout from '@components/MyRecordLayout.tsx';
|
|
54
54
|
* ---
|
|
55
55
|
* <RecordFetcher Layout={MyLayout} client:load />
|
|
@@ -32,7 +32,7 @@ export interface UseRecordFetcherResult {
|
|
|
32
32
|
* @example
|
|
33
33
|
* ```tsx
|
|
34
34
|
* // src/components/RecordView.tsx
|
|
35
|
-
* import { useRecordFetcher } from '@lad-sapienza/scms-core/components/Record
|
|
35
|
+
* import { useRecordFetcher } from '@lad-sapienza/scms-core/components/Record';
|
|
36
36
|
*
|
|
37
37
|
* export default function RecordView() {
|
|
38
38
|
* const { record, loading, error, table, id } = useRecordFetcher();
|
package/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { default as ThemeToggle } from './components/ThemeToggle';
|
|
|
8
8
|
export { DataTb, CsvSource, JsonSource, DirectusSource, ApiSource } from './components/DataTb';
|
|
9
9
|
|
|
10
10
|
// Map components
|
|
11
|
-
export { Map
|
|
11
|
+
export { Map } from './components/Map';
|
|
12
12
|
export { SearchUI, SearchUISimple, SearchUIAdvanced } from './components/Map/Search';
|
|
13
13
|
|
|
14
14
|
// ZoteroGeoViewer component
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lad-sapienza/scms-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Framework components and Astro integrations for s:CMS — DataTb, Gallery, Map, ZoteroGeoViewer, Record.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BSD-0-Clause",
|
|
@@ -10,10 +10,32 @@
|
|
|
10
10
|
},
|
|
11
11
|
"author": "Julian Bogdani <julian.bogdani@uniroma1.it>",
|
|
12
12
|
"main": "./index.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./index.ts",
|
|
15
|
+
"./scms": "./scms.ts",
|
|
16
|
+
"./components/Map": "./components/Map/index.ts",
|
|
17
|
+
"./components/DataTb": "./components/DataTb/index.ts",
|
|
18
|
+
"./components/DataTb/types": "./components/DataTb/types.ts",
|
|
19
|
+
"./components/Gallery": "./components/Gallery/index.ts",
|
|
20
|
+
"./components/Gallery/Gallery.astro": "./components/Gallery/Gallery.astro",
|
|
21
|
+
"./components/Record": "./components/Record/index.ts",
|
|
22
|
+
"./components/ZoteroGeoViewer": "./components/ZoteroGeoViewer/index.ts",
|
|
23
|
+
"./components/TableOfContents/TableOfContents.astro": "./components/TableOfContents/TableOfContents.astro",
|
|
24
|
+
"./components/SEO/SEO.astro": "./components/SEO/SEO.astro",
|
|
25
|
+
"./components/BSNavbar": "./components/BSNavbar.tsx",
|
|
26
|
+
"./components/LocaleSwitcher": "./components/LocaleSwitcher.tsx",
|
|
27
|
+
"./components/ThemeToggle": "./components/ThemeToggle.tsx",
|
|
28
|
+
"./components/RedirectPage/RedirectPage.astro": "./components/RedirectPage/RedirectPage.astro",
|
|
29
|
+
"./components/i18n": "./components/i18n/index.ts",
|
|
30
|
+
"./components/i18n/I18nInit.astro": "./components/i18n/I18nInit.astro",
|
|
31
|
+
"./integrations/directusLoader": "./integrations/directusLoader.ts",
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
13
34
|
"bin": {
|
|
14
35
|
"scms-add-collection": "./bin/add-collection.mjs",
|
|
15
36
|
"scms-add-content": "./bin/add-content.mjs",
|
|
16
|
-
"scms-create": "./bin/create.mjs"
|
|
37
|
+
"scms-create": "./bin/create.mjs",
|
|
38
|
+
"scms-optimize-images": "./bin/optimize-images.mjs"
|
|
17
39
|
},
|
|
18
40
|
"files": [
|
|
19
41
|
"index.ts",
|
|
@@ -35,7 +57,7 @@
|
|
|
35
57
|
"@types/react": "^19.2.14",
|
|
36
58
|
"@types/react-dom": "^19.2.3",
|
|
37
59
|
"astro": "^7.2.4",
|
|
38
|
-
"maplibre-gl": "^
|
|
60
|
+
"maplibre-gl": "^6.7.0",
|
|
39
61
|
"react": "^19.2.4",
|
|
40
62
|
"react-dom": "^19.2.4"
|
|
41
63
|
},
|
|
@@ -48,12 +70,13 @@
|
|
|
48
70
|
"@tanstack/react-table": "^8.21.3",
|
|
49
71
|
"@types/geojson": "^7946.0.16",
|
|
50
72
|
"@types/papaparse": "^5.5.2",
|
|
51
|
-
"@vis.gl/react-maplibre": "^8.1.
|
|
73
|
+
"@vis.gl/react-maplibre": "^8.1.3",
|
|
52
74
|
"astro-expressive-code": "^0.44.1",
|
|
53
75
|
"lucide-react": "^1.8.0",
|
|
54
76
|
"papaparse": "^5.5.3",
|
|
55
77
|
"photoswipe": "^5.4.4",
|
|
56
78
|
"react-photoswipe-gallery": "^4.0.0",
|
|
79
|
+
"sharp": "^0.35.3",
|
|
57
80
|
"zod": "^4.3.6"
|
|
58
81
|
},
|
|
59
82
|
"devDependencies": {
|
package/scms.ts
CHANGED
|
@@ -36,6 +36,13 @@ export interface ScmsOptions {
|
|
|
36
36
|
pagesDir?: string;
|
|
37
37
|
/** Path to shared galleries, relative to the project root. Defaults to 'src/galleries'. */
|
|
38
38
|
galleriesDir?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Link MapLibre's stylesheet (`maplibre-gl/dist/maplibre-gl.css`, ~83 KB /
|
|
41
|
+
* ~11 KB gzipped) from every page — see `scmsMapCssIntegration`. Defaults to
|
|
42
|
+
* `true`. Set `false` for sites that never render `<Map>`, or that import the
|
|
43
|
+
* stylesheet themselves.
|
|
44
|
+
*/
|
|
45
|
+
mapCss?: boolean;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
/** react, react-dom, and any library that calls hooks internally (@tanstack/react-table) — see file doc comment. */
|
|
@@ -64,22 +71,34 @@ function scmsViteConfigIntegration(): AstroIntegration {
|
|
|
64
71
|
dedupe: HOOK_LIBRARIES,
|
|
65
72
|
},
|
|
66
73
|
optimizeDeps: {
|
|
67
|
-
// papaparse is CommonJS-only (no `module`/`exports` field)
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
// it
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
// papaparse is CommonJS-only (no `module`/`exports` field). Its
|
|
75
|
+
// importer (CsvSource.tsx) lives in node_modules once this is a
|
|
76
|
+
// published package, so Vite's dev-time dependency scanner no
|
|
77
|
+
// longer discovers it on its own and pre-bundles the CJS→ESM
|
|
78
|
+
// interop — without this entry the browser is served the raw CJS
|
|
79
|
+
// file and crashes with "does not provide an export named
|
|
80
|
+
// 'default'". Must stay explicit.
|
|
81
|
+
//
|
|
82
|
+
// maplibre-gl used to need the same treatment because v5 shipped a
|
|
83
|
+
// UMD `dist/maplibre-gl.js`; v6 is real ESM (`dist/maplibre-gl.mjs`,
|
|
84
|
+
// `"exports"` map, no UMD), so Vite handles it with no interop
|
|
85
|
+
// shim and no explicit entry here. Map.tsx's `?worker&url` worker
|
|
86
|
+
// chunk is a separate, self-contained module and does not go
|
|
87
|
+
// through this pre-bundle.
|
|
88
|
+
include: ['react', 'react-dom', 'react-dom/client', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'papaparse'],
|
|
89
|
+
},
|
|
90
|
+
ssr: {
|
|
91
|
+
// MapLibre GL JS v6's worker is wired up in Map.tsx via a
|
|
92
|
+
// `maplibre-gl/dist/...?worker&url` import (see that file). Vite's
|
|
93
|
+
// worker plugin can only resolve that specifier when maplibre-gl
|
|
94
|
+
// is bundled for SSR rather than externalised to a raw Node
|
|
95
|
+
// `import`. MapLibre's own Astro guidance calls for this.
|
|
96
|
+
//
|
|
97
|
+
// This is about the worker only. It has no bearing on whether the
|
|
98
|
+
// stylesheet reaches the page — that is a separate problem, with
|
|
99
|
+
// the same symptom under every client directive (`client:load`
|
|
100
|
+
// and `client:only` alike); see `scmsMapCssIntegration`.
|
|
101
|
+
noExternal: ['maplibre-gl'],
|
|
83
102
|
},
|
|
84
103
|
},
|
|
85
104
|
});
|
|
@@ -100,8 +119,40 @@ function scmsThemeInitIntegration(): AstroIntegration {
|
|
|
100
119
|
};
|
|
101
120
|
}
|
|
102
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Links MapLibre's stylesheet from every page.
|
|
124
|
+
*
|
|
125
|
+
* `Map.tsx` imports `maplibre-gl/dist/maplibre-gl.css` itself, which is enough
|
|
126
|
+
* when `<Map>` is imported straight into a page or layout. It is NOT enough
|
|
127
|
+
* for a `<Map>` imported from an MDX content-collection entry whose
|
|
128
|
+
* `render()`ed `Content` is handed down as a prop to another component (e.g.
|
|
129
|
+
* `<ArticlePage Content={Content} />`, which then renders `<Content />` inside
|
|
130
|
+
* a layout): Astro still emits the stylesheet but never links it from the
|
|
131
|
+
* page's HTML, so the layer control, zoom buttons and popups render unstyled
|
|
132
|
+
* in production builds. `astro dev` is unaffected (Vite injects CSS at
|
|
133
|
+
* runtime), which is why it only shows up after `astro build`. Reproduced on
|
|
134
|
+
* Astro 7.2.4 with `client:load` and `client:only="react"`.
|
|
135
|
+
*
|
|
136
|
+
* Importing the stylesheet from `page-ssr` puts it in every page's own module
|
|
137
|
+
* graph, so it is linked regardless of how the MDX is rendered. Costs: one
|
|
138
|
+
* cached, render-blocking ~11 KB (gzipped) request on pages that have no map —
|
|
139
|
+
* hence the `mapCss` opt-out — and, for a `<Map client:only>` imported
|
|
140
|
+
* directly into a page, a second identical-content file (Astro emits the
|
|
141
|
+
* island's copy separately), which is redundant but harmless.
|
|
142
|
+
*/
|
|
143
|
+
function scmsMapCssIntegration(): AstroIntegration {
|
|
144
|
+
return {
|
|
145
|
+
name: 'scms-map-css',
|
|
146
|
+
hooks: {
|
|
147
|
+
'astro:config:setup': ({ injectScript }) => {
|
|
148
|
+
injectScript('page-ssr', "import 'maplibre-gl/dist/maplibre-gl.css';");
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
103
154
|
export function scms(options: ScmsOptions = {}): AstroIntegration[] {
|
|
104
|
-
const { contentDir, pagesDir, galleriesDir } = options;
|
|
155
|
+
const { contentDir, pagesDir, galleriesDir, mapCss = true } = options;
|
|
105
156
|
|
|
106
157
|
return [
|
|
107
158
|
contentAssetsIntegration({ contentDir }),
|
|
@@ -116,5 +167,6 @@ export function scms(options: ScmsOptions = {}): AstroIntegration[] {
|
|
|
116
167
|
sitemap(),
|
|
117
168
|
scmsViteConfigIntegration(),
|
|
118
169
|
scmsThemeInitIntegration(),
|
|
170
|
+
...(mapCss ? [scmsMapCssIntegration()] : []),
|
|
119
171
|
];
|
|
120
172
|
}
|
package/template/README.md.tmpl
CHANGED
|
@@ -14,6 +14,19 @@ Built with [s:CMS](https://github.com/lad-sapienza/scms-core), on top of [Astro]
|
|
|
14
14
|
| `npm run preview` | Preview the production build locally |
|
|
15
15
|
| `npm run add-collection` | Scaffold a new content collection |
|
|
16
16
|
| `npm run add-content` | Add a new content file to an existing collection |
|
|
17
|
+
| `npm run images` | Convert content images to WebP (max 2000 px) and rewrite their references |
|
|
18
|
+
|
|
19
|
+
## Optimizing images
|
|
20
|
+
|
|
21
|
+
Drop JPG/PNG images next to your content as usual, then run `npm run images`: they are converted to WebP, scaled down to 2000 px, the originals are deleted and the `.md`/`.mdx` references are rewritten (`--dry-run` shows the savings without touching anything). References from `.astro`/`.tsx` files are only reported — update them by hand.
|
|
22
|
+
|
|
23
|
+
To make the build fail when an unoptimized image slips in, add a check to `package.json`; it never modifies any file:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
"prebuild": "scms-optimize-images --check"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Limits, quality and the site languages are configured in `src/user.config.mjs` (`userConfig.images`, `userConfig.i18n`); see the [scms-core README](https://github.com/lad-sapienza/scms-core#image-optimization) for all the options, including an optional pre-commit hook. Commit the `.scms-optimize-images.json` file it may create.
|
|
17
30
|
|
|
18
31
|
## Updating the framework
|
|
19
32
|
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"preview": "astro preview",
|
|
11
11
|
"astro": "astro",
|
|
12
12
|
"add-collection": "scms-add-collection",
|
|
13
|
-
"add-content": "scms-add-content"
|
|
13
|
+
"add-content": "scms-add-content",
|
|
14
|
+
"images": "scms-optimize-images"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@astrojs/check": "^0.9.10",
|