Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/traffic-style-icon-pipeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@mapsight/traffic-style": minor
"@mapsight/ui": patch
---

Improve traffic-style icon pipeline: add Font Awesome smart-city pictograms and default ort icons, fix sprite padding and missing default build output, unify sprite/runtime icon fallback in SCSS mixins, and resolve Sass deprecation warnings.

---
12 changes: 5 additions & 7 deletions packages/traffic-style/docs/CUSTOMIZING_SCSS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ overrides into `variables`:
@use "@mapsight/traffic-style/src/scss/icons-2x" with (
$MAPSIGHT_TRAFFIC_STYLE__SPRITE_PATH:
"/img/mapsight-traffic-style-icon-sprite-2x.png?v=2026-01-01",
$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICONS_ENABLED: true,
$MAPSIGHT_TRAFFIC_STYLE__FEATURES_BASE_ZOOM_DEFAULT: 14
);

Expand Down Expand Up @@ -170,13 +169,12 @@ these zoom thresholds. The compact `mapsightIconId` string does not carry varian

### Runtime (composable) icons

| Variable | Default | Effect |
| ------------------------------------------------ | ------- | ---------------------------------------------------- |
| `$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICONS_ENABLED` | `true` | Emit `mapsightRuntimeIcon` rules in `features/_base` |
| `$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICON_SCALE` | `0.5` | Icon scale for client-composed icons |
| Variable | Default | Effect |
| --------------------------------------------- | ------- | ------------------------------------ |
| `$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICON_SCALE` | `0.5` | Icon scale for client-composed icons |

When enabled, composable `mapsightIconId` values are drawn at runtime; sprite ids
are still routed to the sheet via `auto-icon` mixins.
Composable `mapsightIconId` values are drawn at runtime; sprite ids are still
routed to the sheet via `auto-icon` mixins.

### Global geometry and labels

Expand Down
33 changes: 32 additions & 1 deletion packages/traffic-style/docs/CUSTOM_ICON_BUILDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@ Font Awesome pack).
For how sprite vs composable icons are classified, see [ICON_CATALOG.md](ICON_CATALOG.md).
For runtime pictogram packs, see the same doc.

## Monorepo / pnpm workspace

This package uses `publishConfig.linkDirectory: true` so workspace consumers
symlink to `dist/` instead of the package root. That mirrors the published tarball
layout and keeps workspace DX “hot”: apps import built assets from `dist` without
`pnpm pack` or republishing on every traffic-style change.

**Trade-off:** in this setup, pnpm does not reliably expose the `bin` shims
(`traffic-icon-sprite`, `traffic-composable-icons`, …) on `PATH` when you run app
scripts — even though the CLI files exist under
`node_modules/@mapsight/traffic-style/scripts/`. After `pnpm install` from the
registry, the bare command names work as documented below.

**Workaround in workspace apps:** invoke the script explicitly:

```json
{
"scripts": {
"build:iconSprite": "node node_modules/@mapsight/traffic-style/scripts/traffic-icon-sprite.js --output-scss tmp/ --output-img public/img/ --groups default,education"
}
}
```

Same pattern for `traffic-composable-icons.js`. Use
`node_modules/@mapsight/traffic-style/meta.json` for `--meta-path` unless you are
editing `src/meta.json` locally and have not rebuilt traffic-style yet (then point
at `packages/traffic-style/src/meta.json` temporarily).

---

## Custom sprite sheets
Expand All @@ -33,7 +61,7 @@ pre-optimized icon PNGs in the package. Icons with `"render": "composable"` in

### Example

From a consuming app (similar to `apps/braunschweig`):
In a consuming app's `package.json` (registry install — bare CLI names on `PATH`):

```json
{
Expand All @@ -43,6 +71,9 @@ From a consuming app (similar to `apps/braunschweig`):
}
```

In a pnpm workspace linked to this repo, use the `node node_modules/…/scripts/…`
form from [Monorepo / pnpm workspace](#monorepo--pnpm-workspace) above instead.

### Defaults

| Option | Default |
Expand Down
12 changes: 0 additions & 12 deletions packages/traffic-style/docs/ICON_INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,6 @@ needed in production map bundles.

---

## Disable runtime icons

Set `$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICONS_ENABLED: false` in the **first**
`@use` of `variables` (together with sprite settings). The `icons-2x` shim only
forwards sprite path variables — use the manual pattern from
[CUSTOMIZING_SCSS.md](CUSTOMIZING_SCSS.md) when toggling runtime icons.

Composable catalog icons will not render on the map; sprite `auto-icon` rules still
apply.

---

## Direct API reference

| Import path | Use |
Expand Down
12 changes: 1 addition & 11 deletions packages/traffic-style/docs/RUNTIME_ICONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Dev helpers: `defaultIconCache.getStats()`, `prewarmCatalog()` via `runtime-dev`

### Declaring runtime icons in SCSS

`src/scss/features/_base.scss` (when `$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICONS_ENABLED`):
`src/scss/features/_base.scss`:

```scss
[mapsightIconId] {
Expand Down Expand Up @@ -366,16 +366,6 @@ Variant is selected in SCSS (zoom selectors), not in `mapsightIconId`.

---

## Disabling runtime icons

```scss
$MAPSIGHT_TRAFFIC_STYLE__RUNTIME_ICONS_ENABLED: false;
```

Composable catalog icons will not render on the map (sprite `auto-icon` rules still apply).

---

## Testing

Run unit tests with `pnpm test` in this package.
Expand Down
4 changes: 2 additions & 2 deletions packages/traffic-style/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
"build:composable-icons:svg": "node scripts/dev/build-composable-icons.ts svg",
"build:docs": "run-p build:docs:overview",
"build:docs:overview": "node scripts/dev/create-overview-md.ts ./src/icons/ ../img/mapsight-icons-svg/ > dist/docs/overview.md",
"build:icon-sprites": "run-p build:icon-sprites:*",
"build:icon-sprites": "run-p build:icon-sprites:* && cp dist/mapsight-traffic-style-icon-sprite-*.scss .",
"build:icon-sprites:1x": "node scripts/traffic-icon-sprite.ts ./dist/img/mapsight-icons/ --meta-path dist/meta.json --sprite-name mapsight-traffic-style-icon-sprite-1x",
"build:icon-sprites:2x": "node scripts/traffic-icon-sprite.ts ./dist/img/mapsight-icons-2x/ --meta-path dist/meta.json --sprite-name mapsight-traffic-style-icon-sprite-2x",
"build:icons": "node scripts/optimize-icons.ts --src ./src/icons/ --dest ./dist/img/mapsight-icons/",
Expand All @@ -104,7 +104,7 @@
"build:pictograms:traffic-style": "node scripts/dev/import-pictograms.ts",
"build:scripts": "rimraf dist/scripts && tsc --project tsconfig.scripts.json",
"build:setup": "mkdirp dist/docs && mkdirp dist/img",
"build:styles": "vector-style-compiler src/scss/default.scss --output tmp/mapsight-vector-styles --name default && cp tmp/mapsight-vector-styles/default.css dist",
"build:styles": "vector-style-compiler src/scss/default.scss --output tmp/mapsight-vector-styles --name default && cp tmp/mapsight-vector-styles/default.js dist && cp tmp/mapsight-vector-styles/default.css dist",
"clean": "rimraf tmp/* dist/*",
"clean-build": "run-s clean build",
"copy": "run-p copy:src copy:misc",
Expand Down
77 changes: 77 additions & 0 deletions packages/traffic-style/scripts/dev/import-fontawesome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@ import {fileURLToPath} from "node:url";

import {
faBicycle,
faBiking,
faBolt,
faBus,
faCar,
faChargingStation,
faCloudRain,
faCloudSunRain,
faDroplet,
faHospital,
faInfo,
faLeaf,
faLocationDot,
faMugHot,
faSchool,
faTemperatureHigh,
faTree,
faUsers,
faUtensils,
faVanShuttle,
faWater,
} from "@fortawesome/free-solid-svg-icons";
import type {IconDefinition} from "@fortawesome/free-solid-svg-icons";

Expand Down Expand Up @@ -98,6 +108,73 @@ const icons: FaIconEntry[] = [
label: {de: "Marker", en: "Marker"},
icon: faLocationDot,
},
// Smart City
{
exportName: "faWater",
id: "fa-water",
label: {de: "Wasser", en: "Water"},
icon: faWater,
},
{
exportName: "faDroplet",
id: "fa-water-lower",
label: {de: "Niedriger Wasserstand", en: "Low water level"},
icon: faDroplet,
},
{
exportName: "faBiking",
id: "fa-biking",
label: {de: "Radverkehr", en: "Cycling"},
icon: faBiking,
},
{
exportName: "faUsers",
id: "fa-users",
label: {de: "Personen", en: "People"},
icon: faUsers,
},
{
exportName: "faVanShuttle",
id: "fa-car-bus",
label: {de: "Verkehr", en: "Traffic"},
icon: faVanShuttle,
},
{
exportName: "faCloudRain",
id: "fa-cloud-rain",
label: {de: "Regen", en: "Rain"},
icon: faCloudRain,
},
{
exportName: "faCloudSunRain",
id: "fa-thunderstorm-sun",
label: {de: "Gewitter", en: "Thunderstorm"},
icon: faCloudSunRain,
},
{
exportName: "faTree",
id: "fa-tree-alt",
label: {de: "Bäume", en: "Trees"},
icon: faTree,
},
{
exportName: "faLeaf",
id: "fa-leaf-heart",
label: {de: "Umwelt", en: "Environment"},
icon: faLeaf,
},
{
exportName: "faInfo",
id: "fa-info",
label: {de: "Info", en: "Info"},
icon: faInfo,
},
{
exportName: "faTemperatureHigh",
id: "fa-temperature-high",
label: {de: "Temperatur", en: "Temperature"},
icon: faTemperatureHigh,
},
];

function iconToMarkup(icon: IconDefinition): {viewBox: string; markup: string} {
Expand Down
9 changes: 8 additions & 1 deletion packages/traffic-style/scripts/lib/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ export const IconVariantSchema = z.stringFormat(
export type IconId = z.infer<typeof IconIdSchema>;
export const IconIdSchema = z.stringFormat("mapsight-icon-id", /[0-9a-z-]+/);

/** Platform ids and legacy names may use camelCase (e.g. bicycleCount). */
export type IconAlias = z.infer<typeof IconAliasSchema>;
export const IconAliasSchema = z.stringFormat(
"mapsight-icon-alias",
/[0-9a-zA-Z-]+/,
);

export type LangCode = z.infer<typeof LangCodeSchema>;
export const LangCodeSchema = z.stringFormat("mapsight-lang-code", /[a-z]{2}/);

Expand All @@ -33,7 +40,7 @@ export const IconMetaSchema = z.object({
// and string values for the text.
id: IconIdSchema,
label: z.record(LangCodeSchema, z.string()).optional(),
aliases: z.array(IconIdSchema).optional(),
aliases: z.array(IconAliasSchema).optional(),
groups: z.array(IconGroupNameSchema).optional(),
render: IconRenderModeSchema.optional(),
colors: IconColorsSchema.optional(),
Expand Down
6 changes: 2 additions & 4 deletions packages/traffic-style/scripts/traffic-icon-sprite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,8 @@ async function buildIcons(opts: Options): Promise<void> {
});
const composites = items.map((item) => ({
input: item.meta.buffer,
left: item.x,
top: item.y,
width: item.width,
height: item.height,
left: item.x + marginNum,
top: item.y + marginNum,
}));
await spriteSharp.composite(composites).png({effort: 10}).toFile(pngFile);
console.log(`Generated PNG: ${pngFile} (${layoutWidth}x${layoutHeight})`);
Expand Down
1 change: 1 addition & 0 deletions packages/traffic-style/src/icons/ort-default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/traffic-style/src/icons/ort-plain.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/traffic-style/src/icons/ort-small.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/traffic-style/src/icons/ort-xsmall.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/traffic-style/src/lib/icon-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ type SourceMeta = {
const sourceMeta = meta as SourceMeta;

export function getIconRenderMode(id: string): IconRenderMode {
const icon = sourceMeta.icons?.[id];
const baseId = id.split("/")[0]!;
const icon = sourceMeta.icons?.[baseId];
return icon?.render ?? "sprite";
}

Expand Down
Loading
Loading