mirror of
https://github.com/home-assistant/frontend.git
synced 2026-09-29 00:11:31 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9985c56b5 | ||
|
|
49e7e3a7ec | ||
|
|
358cc8a3fa | ||
|
|
6dcdf37fbc | ||
|
|
797b8564ba | ||
|
|
fcc48aa312 | ||
|
|
991c146d90 | ||
|
|
47633c3bd7 | ||
|
|
dafb7f46af |
@@ -76,6 +76,9 @@ jobs:
|
||||
- name: Check dependency licenses
|
||||
if: ${{ !cancelled() && steps.build_resources.outcome == 'success' }}
|
||||
run: yarn run lint:licenses
|
||||
- name: Check the bundled map sprite sheet
|
||||
if: ${{ !cancelled() }}
|
||||
run: ./node_modules/.bin/gulp check-map-sprites
|
||||
test:
|
||||
name: Run tests
|
||||
needs: prepare-dependencies
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
CLA.md
|
||||
CODE_OF_CONDUCT.md
|
||||
LICENSE.md
|
||||
PULL_REQUEST_TEMPLATE.md
|
||||
PULL_REQUEST_TEMPLATE.md
|
||||
public/static/map/sprites/*.json
|
||||
|
||||
@@ -15,6 +15,7 @@ import "./gen-sensor-entity-constants.js";
|
||||
import "./landing-page.js";
|
||||
import "./locale-data.js";
|
||||
import "./map-assets.js";
|
||||
import "./map-sprites.js";
|
||||
import "./rspack.js";
|
||||
import "./service-worker.js";
|
||||
import "./translations.js";
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
// Generates the MapLibre styles for the vector base map.
|
||||
//
|
||||
// Only the styles. Glyphs, sprites and tiles are served by core's proxy, which
|
||||
// is what lets them be requested with an application User-Agent and without a
|
||||
// referrer. The styles stay here because they come from @versatiles/style and
|
||||
// core has no node toolchain to regenerate them with.
|
||||
// Only the styles. Glyphs and tiles are served by core's proxy, which is what
|
||||
// lets them be requested with an application User-Agent and without a referrer.
|
||||
// The sprite sheet ships with the frontend (see map-sprites.js). The styles
|
||||
// stay here because they come from @versatiles/style and core has no node
|
||||
// toolchain to regenerate them with.
|
||||
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { colorful, eclipse } from "@versatiles/style";
|
||||
import { osm } from "@versatiles/style";
|
||||
import fs from "fs-extra";
|
||||
import gulp from "gulp";
|
||||
import paths from "../paths.cjs";
|
||||
import { addLatinLabels } from "./map-labels.js";
|
||||
import {
|
||||
missingSprites,
|
||||
SHEET_FILES,
|
||||
SPRITE_SHEET,
|
||||
spritesDir,
|
||||
} from "./map-sprites.js";
|
||||
|
||||
const PROXY_PATH = "/api/map_tiles";
|
||||
const TILEJSON_URL = `${PROXY_PATH}/tilejson.json`;
|
||||
@@ -50,26 +58,68 @@ const useTileJson = (name, style) => {
|
||||
return style;
|
||||
};
|
||||
|
||||
const styleOptions = {
|
||||
// Keeps the generated URLs origin relative.
|
||||
baseUrl: "",
|
||||
glyphs: `${PROXY_PATH}/fonts/{fontstack}/{range}.pbf`,
|
||||
sprite: [{ id: "basics", url: `${PROXY_PATH}/sprites/basics/sprites` }],
|
||||
// Core serves /static with a month of max-age, so a re-vendored sheet would
|
||||
// otherwise keep being read from cache next to a style that expects the new one.
|
||||
const sheetHash = async () => {
|
||||
const contents = await Promise.all(
|
||||
SHEET_FILES.map((file) => readFile(path.join(spritesDir, file)))
|
||||
);
|
||||
const hash = createHash("sha256");
|
||||
contents.forEach((content) => hash.update(content));
|
||||
return hash.digest("hex").slice(0, 8);
|
||||
};
|
||||
|
||||
const styleOptions = (spriteVersion) => ({
|
||||
urls: {
|
||||
// Keeps the generated URLs origin relative.
|
||||
base: "",
|
||||
glyphsPattern: `${PROXY_PATH}/fonts/{fontstack}/{range}.pbf`,
|
||||
sprite: [
|
||||
{
|
||||
id: SPRITE_SHEET,
|
||||
url: `/static/map/sprites/${SPRITE_SHEET}?v=${spriteVersion}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const checkSprites = (name, style, sheet) => {
|
||||
const missing = missingSprites(style, sheet);
|
||||
if (missing.length) {
|
||||
throw new Error(
|
||||
`Style "${name}" references icons missing from the bundled ${SPRITE_SHEET} ` +
|
||||
`sprite sheet: ${missing.join(", ")}. Run \`yarn gulp update-map-sprites\` ` +
|
||||
`and commit the result.`
|
||||
);
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
// Both themes up front: dark is a real cartography, not an inverted raster.
|
||||
const THEMES = [
|
||||
["light", "colorful"],
|
||||
["dark", "colorful-dark"],
|
||||
];
|
||||
|
||||
const generateStyles = async () => {
|
||||
const sheet = await fs.readJson(
|
||||
path.join(spritesDir, `${SPRITE_SHEET}.json`)
|
||||
);
|
||||
const options = styleOptions(await sheetHash());
|
||||
return THEMES.map(([name, theme]) => [
|
||||
name,
|
||||
addLatinLabels(
|
||||
checkSprites(name, useTileJson(name, osm({ theme, ...options })), sheet)
|
||||
),
|
||||
]);
|
||||
};
|
||||
|
||||
const buildMapAssets = async () => {
|
||||
await fs.emptyDir(outputDir);
|
||||
|
||||
const styles = await generateStyles();
|
||||
await Promise.all(
|
||||
// Both themes up front: dark is a real cartography, not an inverted raster.
|
||||
[
|
||||
["light", colorful],
|
||||
["dark", eclipse],
|
||||
].map(([name, builder]) =>
|
||||
writeFile(
|
||||
path.join(outputDir, `${name}.json`),
|
||||
JSON.stringify(addLatinLabels(useTileJson(name, builder(styleOptions))))
|
||||
)
|
||||
styles.map(([name, style]) =>
|
||||
writeFile(path.join(outputDir, `${name}.json`), JSON.stringify(style))
|
||||
)
|
||||
);
|
||||
};
|
||||
@@ -83,4 +133,8 @@ export const ensureMapAssets = () => {
|
||||
|
||||
gulp.task("build-map-assets", ensureMapAssets);
|
||||
|
||||
// Runs in the required lint job so a @versatiles/style bump that needs new
|
||||
// icons cannot merge before the sheet is re-vendored on that branch.
|
||||
gulp.task("check-map-sprites", generateStyles);
|
||||
|
||||
export const mapAssetsDir = outputDir;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
import { Readable } from "node:stream";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import gulp from "gulp";
|
||||
import paths from "../paths.cjs";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
export const SPRITE_SHEET = "base";
|
||||
export const spritesDir = path.resolve(
|
||||
paths.root_dir,
|
||||
"public",
|
||||
"static",
|
||||
"map",
|
||||
"sprites"
|
||||
);
|
||||
|
||||
export const SHEET_FILES = [".json", ".png", "@2x.json", "@2x.png"].map(
|
||||
(suffix) => `${SPRITE_SHEET}${suffix}`
|
||||
);
|
||||
|
||||
// The only style properties that resolve to a sprite image.
|
||||
const IMAGE_PROPERTIES = [
|
||||
"icon-image",
|
||||
"fill-pattern",
|
||||
"line-pattern",
|
||||
"fill-extrusion-pattern",
|
||||
"background-pattern",
|
||||
];
|
||||
|
||||
const collectStrings = (value, into) => {
|
||||
if (typeof value === "string") {
|
||||
into.push(value);
|
||||
} else if (Array.isArray(value)) {
|
||||
value.forEach((item) => collectStrings(item, into));
|
||||
} else if (value && typeof value === "object") {
|
||||
Object.values(value).forEach((item) => collectStrings(item, into));
|
||||
}
|
||||
return into;
|
||||
};
|
||||
|
||||
export const spriteIds = (style) => {
|
||||
const prefix = `${SPRITE_SHEET}:`;
|
||||
const strings = style.layers.flatMap((layer) =>
|
||||
IMAGE_PROPERTIES.flatMap((property) =>
|
||||
collectStrings([layer.layout?.[property], layer.paint?.[property]], [])
|
||||
)
|
||||
);
|
||||
return new Set(
|
||||
strings
|
||||
.filter((value) => value.startsWith(prefix))
|
||||
.map((value) => value.slice(prefix.length))
|
||||
);
|
||||
};
|
||||
|
||||
export const missingSprites = (style, sheet) =>
|
||||
[...spriteIds(style)].filter((id) => !(id in sheet));
|
||||
|
||||
gulp.task("update-map-sprites", async () => {
|
||||
const { version } = require("@versatiles/style/package.json");
|
||||
const url = `https://github.com/versatiles-org/versatiles-style/releases/download/v${version}/sprites.tar.gz`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error(`Failed to fetch ${url}: ${response.status}`);
|
||||
}
|
||||
|
||||
const tar = spawn("tar", ["-xzf", "-", "-C", spritesDir, ...SHEET_FILES], {
|
||||
stdio: ["pipe", "inherit", "inherit"],
|
||||
});
|
||||
const exited = new Promise((resolve, reject) => {
|
||||
tar.on("error", reject);
|
||||
tar.on("close", (code) =>
|
||||
code === 0 ? resolve() : reject(new Error(`tar exited with ${code}`))
|
||||
);
|
||||
});
|
||||
await pipeline(Readable.fromWeb(response.body), tar.stdin);
|
||||
await exited;
|
||||
});
|
||||
+1
-1
@@ -169,7 +169,7 @@
|
||||
"@types/sortablejs": "1.15.9",
|
||||
"@types/tar": "7.0.87",
|
||||
"@typescript/native": "npm:[email protected]",
|
||||
"@versatiles/style": "5.13.1",
|
||||
"@versatiles/style": "6.0.1",
|
||||
"@vitest/coverage-v8": "5.0.2",
|
||||
"babel-loader": "10.1.1",
|
||||
"babel-plugin-polyfill-corejs3": "1.0.0",
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"icon-airfield": {"width":32,"height":32,"x":0,"y":0,"pixelRatio":1,"sdf":true,"title":"Airfield","aliases":["aerodrome","airstrip","landing strip"]},
|
||||
"icon-airport": {"width":32,"height":32,"x":32,"y":0,"pixelRatio":1,"sdf":true,"title":"Airport","aliases":["aeroplane","airplane","plane","flight","terminal"]},
|
||||
"icon-alcohol_shop": {"width":32,"height":32,"x":0,"y":32,"pixelRatio":1,"sdf":true,"title":"Alcohol shop","aliases":["off-licence","liquor store","bottle shop","wine","spirits"]},
|
||||
"icon-amusement_park": {"width":32,"height":32,"x":32,"y":32,"pixelRatio":1,"sdf":true,"title":"Amusement park","aliases":["theme park","fairground","rides"]},
|
||||
"icon-art_gallery": {"width":32,"height":32,"x":64,"y":0,"pixelRatio":1,"sdf":true,"title":"Art gallery","aliases":["picture","painting","exhibition"]},
|
||||
"icon-artwork": {"width":32,"height":32,"x":64,"y":32,"pixelRatio":1,"sdf":true,"title":"Artwork","aliases":["public art","sculpture","installation"]},
|
||||
"icon-atm": {"width":32,"height":32,"x":0,"y":64,"pixelRatio":1,"sdf":true,"title":"ATM","aliases":["cash machine","cashpoint","bank machine"]},
|
||||
"icon-bakery": {"width":32,"height":32,"x":32,"y":64,"pixelRatio":1,"sdf":true,"title":"Bakery","aliases":["bread","baker","patisserie"]},
|
||||
"icon-bank": {"width":32,"height":32,"x":64,"y":64,"pixelRatio":1,"sdf":true,"title":"Bank","aliases":["branch","banking","finance"]},
|
||||
"icon-bar": {"width":32,"height":32,"x":96,"y":0,"pixelRatio":1,"sdf":true,"title":"Bar","aliases":["cocktail","drinks","lounge"]},
|
||||
"icon-beauty": {"width":32,"height":32,"x":96,"y":32,"pixelRatio":1,"sdf":true,"title":"Beauty salon","aliases":["cosmetics","nails","spa"]},
|
||||
"icon-beer_mug": {"width":32,"height":32,"x":96,"y":64,"pixelRatio":1,"sdf":true,"title":"Beer mug","aliases":["beer","beergarden","beer garden","brewery"]},
|
||||
"icon-bench": {"width":32,"height":32,"x":0,"y":96,"pixelRatio":1,"sdf":true,"title":"Bench","aliases":["seat","seating","rest"]},
|
||||
"icon-beverages": {"width":32,"height":32,"x":32,"y":96,"pixelRatio":1,"sdf":true,"title":"Drinks shop","aliases":["soft drinks","juice","off-licence"]},
|
||||
"icon-bicycle_share": {"width":32,"height":32,"x":64,"y":96,"pixelRatio":1,"sdf":true,"title":"Bike share","aliases":["bicycle sharing","hire","docking station"]},
|
||||
"icon-books": {"width":32,"height":32,"x":96,"y":96,"pixelRatio":1,"sdf":true,"title":"Bookshop","aliases":["bookstore","reading","literature"]},
|
||||
"icon-bus": {"width":32,"height":32,"x":128,"y":0,"pixelRatio":1,"sdf":true,"title":"Bus","aliases":["coach","omnibus","public transport"]},
|
||||
"icon-butcher": {"width":32,"height":32,"x":128,"y":32,"pixelRatio":1,"sdf":true,"title":"Butcher","aliases":["meat","deli","carvery"]},
|
||||
"icon-cafe": {"width":32,"height":32,"x":128,"y":64,"pixelRatio":1,"sdf":true,"title":"Café","aliases":["coffee","coffee shop","espresso","tea"]},
|
||||
"icon-campsite": {"width":32,"height":32,"x":128,"y":96,"pixelRatio":1,"sdf":true,"title":"Campsite","aliases":["camping","tent","pitch"]},
|
||||
"icon-car_rental": {"width":32,"height":32,"x":0,"y":128,"pixelRatio":1,"sdf":true,"title":"Car rental","aliases":["car hire","rent a car"]},
|
||||
"icon-car_wash": {"width":32,"height":32,"x":32,"y":128,"pixelRatio":1,"sdf":true,"title":"Car wash","aliases":["valeting","vehicle wash"]},
|
||||
"icon-caravan": {"width":32,"height":32,"x":64,"y":128,"pixelRatio":1,"sdf":true,"title":"Caravan site","aliases":["motorhome","rv","campervan"]},
|
||||
"icon-castle": {"width":32,"height":32,"x":96,"y":128,"pixelRatio":1,"sdf":true,"title":"Castle","aliases":["fort","fortress","palace","chateau"]},
|
||||
"icon-cemetery": {"width":32,"height":32,"x":128,"y":128,"pixelRatio":1,"sdf":true,"title":"Cemetery","aliases":["graveyard","burial","grave"]},
|
||||
"icon-chalet": {"width":32,"height":32,"x":160,"y":0,"pixelRatio":1,"sdf":true,"title":"Chalet","aliases":["cabin","lodge","holiday home"]},
|
||||
"icon-cinema": {"width":32,"height":32,"x":160,"y":32,"pixelRatio":1,"sdf":true,"title":"Cinema","aliases":["movie theater","movies","film"]},
|
||||
"icon-clothes": {"width":32,"height":32,"x":160,"y":64,"pixelRatio":1,"sdf":true,"title":"Clothes shop","aliases":["clothing","fashion","apparel","boutique"]},
|
||||
"icon-college": {"width":32,"height":32,"x":160,"y":96,"pixelRatio":1,"sdf":true,"title":"College","aliases":["university","campus","further education"]},
|
||||
"icon-community": {"width":32,"height":32,"x":160,"y":128,"pixelRatio":1,"sdf":true,"title":"Community centre","aliases":["community center","village hall","meeting"]},
|
||||
"icon-defibrillator": {"width":32,"height":32,"x":0,"y":160,"pixelRatio":1,"sdf":true,"title":"Defibrillator","aliases":["aed","heart","resuscitation","emergency"]},
|
||||
"icon-dentist": {"width":32,"height":32,"x":32,"y":160,"pixelRatio":1,"sdf":true,"title":"Dentist","aliases":["dental","teeth","orthodontist"]},
|
||||
"icon-dharma_wheel": {"width":32,"height":32,"x":64,"y":160,"pixelRatio":1,"sdf":true,"title":"Dharma wheel","aliases":["buddhist","buddhism","temple","religion"]},
|
||||
"icon-do_it_yourself": {"width":32,"height":32,"x":96,"y":160,"pixelRatio":1,"sdf":true,"title":"DIY store","aliases":["doityourself","home improvement","builders merchant"]},
|
||||
"icon-doctor": {"width":32,"height":32,"x":128,"y":160,"pixelRatio":1,"sdf":true,"title":"Doctor","aliases":["gp","surgery","clinic","physician"]},
|
||||
"icon-dog": {"width":32,"height":32,"x":160,"y":160,"pixelRatio":1,"sdf":true,"title":"Dog park","aliases":["dog_park","dogs","pet","off-leash"]},
|
||||
"icon-drinking_water": {"width":32,"height":32,"x":192,"y":0,"pixelRatio":1,"sdf":true,"title":"Drinking water","aliases":["tap","potable","refill","water point"]},
|
||||
"icon-dry_cleaning": {"width":32,"height":32,"x":192,"y":32,"pixelRatio":1,"sdf":true,"title":"Dry cleaning","aliases":["drycleaning","cleaner","launderer"]},
|
||||
"icon-embassy": {"width":32,"height":32,"x":192,"y":64,"pixelRatio":1,"sdf":true,"title":"Embassy","aliases":["consulate","diplomatic","mission"]},
|
||||
"icon-emergency_access": {"width":32,"height":32,"x":192,"y":96,"pixelRatio":1,"sdf":true,"title":"Emergency access","aliases":["access point","rescue point"]},
|
||||
"icon-emergency_phone": {"width":32,"height":32,"x":192,"y":128,"pixelRatio":1,"sdf":true,"title":"Emergency phone","aliases":["sos","help point","call box"]},
|
||||
"icon-fast_food": {"width":32,"height":32,"x":192,"y":160,"pixelRatio":1,"sdf":true,"title":"Fast food","aliases":["takeaway","burger","snack"]},
|
||||
"icon-fire_station": {"width":32,"height":32,"x":0,"y":192,"pixelRatio":1,"sdf":true,"title":"Fire station","aliases":["fire brigade","fire service","firefighters"]},
|
||||
"icon-florist": {"width":32,"height":32,"x":32,"y":192,"pixelRatio":1,"sdf":true,"title":"Florist","aliases":["flowers","flower shop","bouquet"]},
|
||||
"icon-fountain": {"width":32,"height":32,"x":64,"y":192,"pixelRatio":1,"sdf":true,"title":"Fountain","aliases":["water feature","jet"]},
|
||||
"icon-fuel_pump": {"width":32,"height":32,"x":96,"y":192,"pixelRatio":1,"sdf":true,"title":"Petrol station","aliases":["fuel","gas station","filling station","diesel"]},
|
||||
"icon-furniture": {"width":32,"height":32,"x":128,"y":192,"pixelRatio":1,"sdf":true,"title":"Furniture shop","aliases":["furnishings","home store"]},
|
||||
"icon-garden_center": {"width":32,"height":32,"x":160,"y":192,"pixelRatio":1,"sdf":true,"title":"Garden centre","aliases":["garden_centre","nursery","plants"]},
|
||||
"icon-gift": {"width":32,"height":32,"x":192,"y":192,"pixelRatio":1,"sdf":true,"title":"Gift shop","aliases":["presents","souvenirs"]},
|
||||
"icon-golf": {"width":32,"height":32,"x":224,"y":0,"pixelRatio":1,"sdf":true,"title":"Golf","aliases":["golf course","driving range"]},
|
||||
"icon-greengrocer": {"width":32,"height":32,"x":224,"y":32,"pixelRatio":1,"sdf":true,"title":"Greengrocer","aliases":["fruit","vegetables","produce"]},
|
||||
"icon-hardware": {"width":32,"height":32,"x":224,"y":64,"pixelRatio":1,"sdf":true,"title":"Hardware shop","aliases":["tools","ironmonger"]},
|
||||
"icon-historic": {"width":32,"height":32,"x":224,"y":96,"pixelRatio":1,"sdf":true,"title":"Historic site","aliases":["heritage","ruins","antiquity"]},
|
||||
"icon-hospital": {"width":32,"height":32,"x":224,"y":128,"pixelRatio":1,"sdf":true,"title":"Hospital","aliases":["a&e","emergency room","infirmary","medical"]},
|
||||
"icon-hunting_stand": {"width":32,"height":32,"x":224,"y":160,"pixelRatio":1,"sdf":true,"title":"Hunting stand","aliases":["huntingstand","hide","deer stand"]},
|
||||
"icon-hydrant": {"width":32,"height":32,"x":224,"y":192,"pixelRatio":1,"sdf":true,"title":"Fire hydrant","aliases":["fire plug","water point","firefighting"]},
|
||||
"icon-ice_rink": {"width":32,"height":32,"x":0,"y":224,"pixelRatio":1,"sdf":true,"title":"Ice rink","aliases":["icerink","skating","ice skating"]},
|
||||
"icon-justice": {"width":32,"height":32,"x":32,"y":224,"pixelRatio":1,"sdf":true,"title":"Courthouse","aliases":["court","law court","tribunal","judiciary"]},
|
||||
"icon-khanda": {"width":32,"height":32,"x":64,"y":224,"pixelRatio":1,"sdf":true,"title":"Khanda","aliases":["sikh","sikhism","gurdwara","religion"]},
|
||||
"icon-latin_cross": {"width":32,"height":32,"x":96,"y":224,"pixelRatio":1,"sdf":true,"title":"Latin cross","aliases":["christian","christianity","church","religion"]},
|
||||
"icon-laundry": {"width":32,"height":32,"x":128,"y":224,"pixelRatio":1,"sdf":true,"title":"Laundry","aliases":["launderette","laundromat","washing"]},
|
||||
"icon-library": {"width":32,"height":32,"x":160,"y":224,"pixelRatio":1,"sdf":true,"title":"Library","aliases":["lending","public library","archive"]},
|
||||
"icon-lighthouse": {"width":32,"height":32,"x":192,"y":224,"pixelRatio":1,"sdf":true,"title":"Lighthouse","aliases":["beacon","navigation","coast"]},
|
||||
"icon-lodging": {"width":32,"height":32,"x":224,"y":224,"pixelRatio":1,"sdf":true,"title":"Hotel","aliases":["accommodation","guest house","hostel","motel","b&b"]},
|
||||
"icon-marketplace": {"width":32,"height":32,"x":256,"y":0,"pixelRatio":1,"sdf":true,"title":"Marketplace","aliases":["market","stalls","bazaar"]},
|
||||
"icon-monument": {"width":32,"height":32,"x":256,"y":32,"pixelRatio":1,"sdf":true,"title":"Monument","aliases":["memorial","statue","landmark"]},
|
||||
"icon-newsagent": {"width":32,"height":32,"x":256,"y":64,"pixelRatio":1,"sdf":true,"title":"Newsagent","aliases":["news","tobacconist","corner shop"]},
|
||||
"icon-newspaper": {"width":32,"height":32,"x":256,"y":96,"pixelRatio":1,"sdf":true,"title":"Newspaper kiosk","aliases":["kiosk","newsstand","press"]},
|
||||
"icon-nightclub": {"width":32,"height":32,"x":256,"y":128,"pixelRatio":1,"sdf":true,"title":"Nightclub","aliases":["club","disco","dancing"]},
|
||||
"icon-nursing_home": {"width":32,"height":32,"x":256,"y":160,"pixelRatio":1,"sdf":true,"title":"Nursing home","aliases":["nursinghome","care home","elderly"]},
|
||||
"icon-observation_tower": {"width":32,"height":32,"x":256,"y":192,"pixelRatio":1,"sdf":true,"title":"Observation tower","aliases":["lookout","viewing tower","watchtower"]},
|
||||
"icon-om": {"width":32,"height":32,"x":256,"y":224,"pixelRatio":1,"sdf":true,"title":"Om","aliases":["hindu","hinduism","temple","religion"]},
|
||||
"icon-optician": {"width":32,"height":32,"x":0,"y":256,"pixelRatio":1,"sdf":true,"title":"Optician","aliases":["glasses","eyewear","optometrist"]},
|
||||
"icon-outdoor": {"width":32,"height":32,"x":32,"y":256,"pixelRatio":1,"sdf":true,"title":"Outdoor shop","aliases":["camping shop","hiking","mountaineering"]},
|
||||
"icon-person_kneeling_and_praying": {"width":32,"height":32,"x":64,"y":256,"pixelRatio":1,"sdf":true,"title":"Place of worship","aliases":["place_of_worship","prayer","worship","religion"]},
|
||||
"icon-picnic_site": {"width":32,"height":32,"x":96,"y":256,"pixelRatio":1,"sdf":true,"title":"Picnic site","aliases":["picnic","picnic table","rest area"]},
|
||||
"icon-pill": {"width":32,"height":32,"x":128,"y":256,"pixelRatio":1,"sdf":true,"title":"Pharmacy","aliases":["chemist","drugstore","medicine","prescription"]},
|
||||
"icon-pint_glass": {"width":32,"height":32,"x":160,"y":256,"pixelRatio":1,"sdf":true,"title":"Pub","aliases":["public house","tavern","inn","beer"]},
|
||||
"icon-pitch": {"width":32,"height":32,"x":192,"y":256,"pixelRatio":1,"sdf":true,"title":"Sports pitch","aliases":["field","court","playing field"]},
|
||||
"icon-police_officer": {"width":32,"height":32,"x":224,"y":256,"pixelRatio":1,"sdf":true,"title":"Police","aliases":["police station","law enforcement","constabulary"]},
|
||||
"icon-post": {"width":32,"height":32,"x":256,"y":256,"pixelRatio":1,"sdf":true,"title":"Post office","aliases":["mail","postal","parcel"]},
|
||||
"icon-postbox": {"width":32,"height":32,"x":288,"y":0,"pixelRatio":1,"sdf":true,"title":"Post box","aliases":["mailbox","letter box","pillar box"]},
|
||||
"icon-prison": {"width":32,"height":32,"x":288,"y":32,"pixelRatio":1,"sdf":true,"title":"Prison","aliases":["jail","correctional","penitentiary"]},
|
||||
"icon-rail": {"width":32,"height":32,"x":288,"y":64,"pixelRatio":1,"sdf":true,"title":"Railway","aliases":["train","railway station","metro","subway"]},
|
||||
"icon-recycling": {"width":32,"height":32,"x":288,"y":96,"pixelRatio":1,"sdf":true,"title":"Recycling","aliases":["bottle bank","waste","recycle centre"]},
|
||||
"icon-restaurant": {"width":32,"height":32,"x":288,"y":128,"pixelRatio":1,"sdf":true,"title":"Restaurant","aliases":["dining","eat","food","bistro"]},
|
||||
"icon-restrooms": {"width":32,"height":32,"x":288,"y":160,"pixelRatio":1,"sdf":true,"title":"Toilets","aliases":["toilet","wc","bathroom","lavatory"]},
|
||||
"icon-ring": {"width":32,"height":32,"x":288,"y":192,"pixelRatio":1,"sdf":true,"title":"Jewellery shop","aliases":["jewelry_store","jeweller","jewelry","rings"]},
|
||||
"icon-rocking_horse": {"width":32,"height":32,"x":288,"y":224,"pixelRatio":1,"sdf":true,"title":"Toy shop","aliases":["toys","toy store","games"]},
|
||||
"icon-school": {"width":32,"height":32,"x":288,"y":256,"pixelRatio":1,"sdf":true,"title":"School","aliases":["primary","secondary","education"]},
|
||||
"icon-scissors_and_comb": {"width":32,"height":32,"x":0,"y":288,"pixelRatio":1,"sdf":true,"title":"Hairdresser","aliases":["barber","salon","haircut","hair"]},
|
||||
"icon-seesaw": {"width":32,"height":32,"x":32,"y":288,"pixelRatio":1,"sdf":true,"title":"Playground","aliases":["play area","swings","children"]},
|
||||
"icon-shelter": {"width":32,"height":32,"x":64,"y":288,"pixelRatio":1,"sdf":true,"title":"Shelter","aliases":["bus shelter","refuge","hut"]},
|
||||
"icon-shoes": {"width":32,"height":32,"x":96,"y":288,"pixelRatio":1,"sdf":true,"title":"Shoe shop","aliases":["footwear","cobbler","trainers"]},
|
||||
"icon-shop": {"width":32,"height":32,"x":128,"y":288,"pixelRatio":1,"sdf":true,"title":"Shop","aliases":["store","retail","convenience"]},
|
||||
"icon-shrine": {"width":32,"height":32,"x":160,"y":288,"pixelRatio":1,"sdf":true,"title":"Shrine","aliases":["wayside shrine","sacred","religion"]},
|
||||
"icon-sports": {"width":32,"height":32,"x":192,"y":288,"pixelRatio":1,"sdf":true,"title":"Sports centre","aliases":["leisure centre","gym","fitness"]},
|
||||
"icon-stadium": {"width":32,"height":32,"x":224,"y":288,"pixelRatio":1,"sdf":true,"title":"Stadium","aliases":["arena","ground","sports ground"]},
|
||||
"icon-star_and_crescent": {"width":32,"height":32,"x":256,"y":288,"pixelRatio":1,"sdf":true,"title":"Star and crescent","aliases":["muslim","islam","mosque","religion"]},
|
||||
"icon-star_of_david": {"width":32,"height":32,"x":288,"y":288,"pixelRatio":1,"sdf":true,"title":"Star of David","aliases":["jewish","judaism","synagogue","religion"]},
|
||||
"icon-stationery": {"width":32,"height":32,"x":320,"y":0,"pixelRatio":1,"sdf":true,"title":"Stationery shop","aliases":["office supplies","pens","paper"]},
|
||||
"icon-surveillance": {"width":32,"height":32,"x":320,"y":32,"pixelRatio":1,"sdf":true,"title":"Surveillance camera","aliases":["cctv","camera","security"]},
|
||||
"icon-swimming": {"width":32,"height":32,"x":320,"y":64,"pixelRatio":1,"sdf":true,"title":"Swimming","aliases":["pool","swimming pool","lido","baths"]},
|
||||
"icon-telephone": {"width":32,"height":32,"x":320,"y":96,"pixelRatio":1,"sdf":true,"title":"Telephone","aliases":["phone","call box","payphone"]},
|
||||
"icon-theater": {"width":32,"height":32,"x":320,"y":128,"pixelRatio":1,"sdf":true,"title":"Theatre","aliases":["playhouse","drama","stage","performing arts"]},
|
||||
"icon-town_hall": {"width":32,"height":32,"x":320,"y":160,"pixelRatio":1,"sdf":true,"title":"Town hall","aliases":["city hall","civic","municipal"]},
|
||||
"icon-travel_agent": {"width":32,"height":32,"x":320,"y":192,"pixelRatio":1,"sdf":true,"title":"Travel agent","aliases":["travel agency","holidays","tours"]},
|
||||
"icon-tube_and_toothbrush": {"width":32,"height":32,"x":320,"y":224,"pixelRatio":1,"sdf":true,"title":"Chemist","aliases":["drugstore","toiletries","health and beauty"]},
|
||||
"icon-vending_machine": {"width":32,"height":32,"x":320,"y":256,"pixelRatio":1,"sdf":true,"title":"Vending machine","aliases":["vendingmachine","vending","automat"]},
|
||||
"icon-veterinary": {"width":32,"height":32,"x":320,"y":288,"pixelRatio":1,"sdf":true,"title":"Vet","aliases":["animal hospital","animal clinic","pets"]},
|
||||
"icon-video": {"width":32,"height":32,"x":0,"y":320,"pixelRatio":1,"sdf":true,"title":"Video shop","aliases":["dvd","video rental","movies"]},
|
||||
"icon-viewpoint": {"width":32,"height":32,"x":32,"y":320,"pixelRatio":1,"sdf":true,"title":"Viewpoint","aliases":["lookout","vista","panorama","scenic"]},
|
||||
"icon-waste_basket": {"width":32,"height":32,"x":64,"y":320,"pixelRatio":1,"sdf":true,"title":"Waste basket","aliases":["bin","litter bin","rubbish","trash"]},
|
||||
"icon-wastewater": {"width":32,"height":32,"x":96,"y":320,"pixelRatio":1,"sdf":true,"title":"Wastewater plant","aliases":["sewage","treatment works","sewer"]},
|
||||
"icon-water_park": {"width":32,"height":32,"x":128,"y":320,"pixelRatio":1,"sdf":true,"title":"Water park","aliases":["waterpark","aquapark","slides"]},
|
||||
"icon-watermill": {"width":32,"height":32,"x":160,"y":320,"pixelRatio":1,"sdf":true,"title":"Watermill","aliases":["mill","water wheel"]},
|
||||
"icon-waterworks": {"width":32,"height":32,"x":192,"y":320,"pixelRatio":1,"sdf":true,"title":"Waterworks","aliases":["water treatment","pumping station","water supply"]},
|
||||
"icon-windmill": {"width":32,"height":32,"x":224,"y":320,"pixelRatio":1,"sdf":true,"title":"Windmill","aliases":["mill","wind mill"]},
|
||||
"icon-yin_yang": {"width":32,"height":32,"x":256,"y":320,"pixelRatio":1,"sdf":true,"title":"Yin and yang","aliases":["taoist","taoism","religion","balance"]},
|
||||
"icon-zoo": {"width":32,"height":32,"x":288,"y":320,"pixelRatio":1,"sdf":true,"title":"Zoo","aliases":["animals","wildlife park","safari"]},
|
||||
"marking-oneway": {"width":14,"height":25,"x":352,"y":32,"pixelRatio":1,"sdf":true,"title":"One-way arrow","aliases":["one way","direction","traffic flow"],"center":[0.5,0]},
|
||||
"pattern-hatched": {"width":16,"height":16,"x":366,"y":32,"pixelRatio":1,"sdf":false,"title":"Diagonal hatching","aliases":["hazard","danger area","stripes","fill"]},
|
||||
"pattern-hatched_thin": {"width":16,"height":16,"x":352,"y":57,"pixelRatio":1,"sdf":false,"title":"Fine diagonal hatching","aliases":["hazard","stripes","fill","light"]},
|
||||
"pattern-striped": {"width":16,"height":16,"x":368,"y":57,"pixelRatio":1,"sdf":false,"title":"Horizontal stripes","aliases":["bands","lines","fill"]},
|
||||
"transport-information": {"width":32,"height":32,"x":320,"y":320,"pixelRatio":1,"sdf":true,"title":"Information","aliases":["info","tourist information","help"]},
|
||||
"transport-tram": {"width":32,"height":32,"x":352,"y":0,"pixelRatio":1,"sdf":true,"title":"Tram","aliases":["streetcar","light rail","trolley"]}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"icon-airfield": {"width":64,"height":64,"x":0,"y":0,"pixelRatio":2,"sdf":true,"title":"Airfield","aliases":["aerodrome","airstrip","landing strip"]},
|
||||
"icon-airport": {"width":64,"height":64,"x":64,"y":0,"pixelRatio":2,"sdf":true,"title":"Airport","aliases":["aeroplane","airplane","plane","flight","terminal"]},
|
||||
"icon-alcohol_shop": {"width":64,"height":64,"x":0,"y":64,"pixelRatio":2,"sdf":true,"title":"Alcohol shop","aliases":["off-licence","liquor store","bottle shop","wine","spirits"]},
|
||||
"icon-amusement_park": {"width":64,"height":64,"x":64,"y":64,"pixelRatio":2,"sdf":true,"title":"Amusement park","aliases":["theme park","fairground","rides"]},
|
||||
"icon-art_gallery": {"width":64,"height":64,"x":128,"y":0,"pixelRatio":2,"sdf":true,"title":"Art gallery","aliases":["picture","painting","exhibition"]},
|
||||
"icon-artwork": {"width":64,"height":64,"x":128,"y":64,"pixelRatio":2,"sdf":true,"title":"Artwork","aliases":["public art","sculpture","installation"]},
|
||||
"icon-atm": {"width":64,"height":64,"x":0,"y":128,"pixelRatio":2,"sdf":true,"title":"ATM","aliases":["cash machine","cashpoint","bank machine"]},
|
||||
"icon-bakery": {"width":64,"height":64,"x":64,"y":128,"pixelRatio":2,"sdf":true,"title":"Bakery","aliases":["bread","baker","patisserie"]},
|
||||
"icon-bank": {"width":64,"height":64,"x":128,"y":128,"pixelRatio":2,"sdf":true,"title":"Bank","aliases":["branch","banking","finance"]},
|
||||
"icon-bar": {"width":64,"height":64,"x":192,"y":0,"pixelRatio":2,"sdf":true,"title":"Bar","aliases":["cocktail","drinks","lounge"]},
|
||||
"icon-beauty": {"width":64,"height":64,"x":192,"y":64,"pixelRatio":2,"sdf":true,"title":"Beauty salon","aliases":["cosmetics","nails","spa"]},
|
||||
"icon-beer_mug": {"width":64,"height":64,"x":192,"y":128,"pixelRatio":2,"sdf":true,"title":"Beer mug","aliases":["beer","beergarden","beer garden","brewery"]},
|
||||
"icon-bench": {"width":64,"height":64,"x":0,"y":192,"pixelRatio":2,"sdf":true,"title":"Bench","aliases":["seat","seating","rest"]},
|
||||
"icon-beverages": {"width":64,"height":64,"x":64,"y":192,"pixelRatio":2,"sdf":true,"title":"Drinks shop","aliases":["soft drinks","juice","off-licence"]},
|
||||
"icon-bicycle_share": {"width":64,"height":64,"x":128,"y":192,"pixelRatio":2,"sdf":true,"title":"Bike share","aliases":["bicycle sharing","hire","docking station"]},
|
||||
"icon-books": {"width":64,"height":64,"x":192,"y":192,"pixelRatio":2,"sdf":true,"title":"Bookshop","aliases":["bookstore","reading","literature"]},
|
||||
"icon-bus": {"width":64,"height":64,"x":256,"y":0,"pixelRatio":2,"sdf":true,"title":"Bus","aliases":["coach","omnibus","public transport"]},
|
||||
"icon-butcher": {"width":64,"height":64,"x":256,"y":64,"pixelRatio":2,"sdf":true,"title":"Butcher","aliases":["meat","deli","carvery"]},
|
||||
"icon-cafe": {"width":64,"height":64,"x":256,"y":128,"pixelRatio":2,"sdf":true,"title":"Café","aliases":["coffee","coffee shop","espresso","tea"]},
|
||||
"icon-campsite": {"width":64,"height":64,"x":256,"y":192,"pixelRatio":2,"sdf":true,"title":"Campsite","aliases":["camping","tent","pitch"]},
|
||||
"icon-car_rental": {"width":64,"height":64,"x":0,"y":256,"pixelRatio":2,"sdf":true,"title":"Car rental","aliases":["car hire","rent a car"]},
|
||||
"icon-car_wash": {"width":64,"height":64,"x":64,"y":256,"pixelRatio":2,"sdf":true,"title":"Car wash","aliases":["valeting","vehicle wash"]},
|
||||
"icon-caravan": {"width":64,"height":64,"x":128,"y":256,"pixelRatio":2,"sdf":true,"title":"Caravan site","aliases":["motorhome","rv","campervan"]},
|
||||
"icon-castle": {"width":64,"height":64,"x":192,"y":256,"pixelRatio":2,"sdf":true,"title":"Castle","aliases":["fort","fortress","palace","chateau"]},
|
||||
"icon-cemetery": {"width":64,"height":64,"x":256,"y":256,"pixelRatio":2,"sdf":true,"title":"Cemetery","aliases":["graveyard","burial","grave"]},
|
||||
"icon-chalet": {"width":64,"height":64,"x":320,"y":0,"pixelRatio":2,"sdf":true,"title":"Chalet","aliases":["cabin","lodge","holiday home"]},
|
||||
"icon-cinema": {"width":64,"height":64,"x":320,"y":64,"pixelRatio":2,"sdf":true,"title":"Cinema","aliases":["movie theater","movies","film"]},
|
||||
"icon-clothes": {"width":64,"height":64,"x":320,"y":128,"pixelRatio":2,"sdf":true,"title":"Clothes shop","aliases":["clothing","fashion","apparel","boutique"]},
|
||||
"icon-college": {"width":64,"height":64,"x":320,"y":192,"pixelRatio":2,"sdf":true,"title":"College","aliases":["university","campus","further education"]},
|
||||
"icon-community": {"width":64,"height":64,"x":320,"y":256,"pixelRatio":2,"sdf":true,"title":"Community centre","aliases":["community center","village hall","meeting"]},
|
||||
"icon-defibrillator": {"width":64,"height":64,"x":0,"y":320,"pixelRatio":2,"sdf":true,"title":"Defibrillator","aliases":["aed","heart","resuscitation","emergency"]},
|
||||
"icon-dentist": {"width":64,"height":64,"x":64,"y":320,"pixelRatio":2,"sdf":true,"title":"Dentist","aliases":["dental","teeth","orthodontist"]},
|
||||
"icon-dharma_wheel": {"width":64,"height":64,"x":128,"y":320,"pixelRatio":2,"sdf":true,"title":"Dharma wheel","aliases":["buddhist","buddhism","temple","religion"]},
|
||||
"icon-do_it_yourself": {"width":64,"height":64,"x":192,"y":320,"pixelRatio":2,"sdf":true,"title":"DIY store","aliases":["doityourself","home improvement","builders merchant"]},
|
||||
"icon-doctor": {"width":64,"height":64,"x":256,"y":320,"pixelRatio":2,"sdf":true,"title":"Doctor","aliases":["gp","surgery","clinic","physician"]},
|
||||
"icon-dog": {"width":64,"height":64,"x":320,"y":320,"pixelRatio":2,"sdf":true,"title":"Dog park","aliases":["dog_park","dogs","pet","off-leash"]},
|
||||
"icon-drinking_water": {"width":64,"height":64,"x":384,"y":0,"pixelRatio":2,"sdf":true,"title":"Drinking water","aliases":["tap","potable","refill","water point"]},
|
||||
"icon-dry_cleaning": {"width":64,"height":64,"x":384,"y":64,"pixelRatio":2,"sdf":true,"title":"Dry cleaning","aliases":["drycleaning","cleaner","launderer"]},
|
||||
"icon-embassy": {"width":64,"height":64,"x":384,"y":128,"pixelRatio":2,"sdf":true,"title":"Embassy","aliases":["consulate","diplomatic","mission"]},
|
||||
"icon-emergency_access": {"width":64,"height":64,"x":384,"y":192,"pixelRatio":2,"sdf":true,"title":"Emergency access","aliases":["access point","rescue point"]},
|
||||
"icon-emergency_phone": {"width":64,"height":64,"x":384,"y":256,"pixelRatio":2,"sdf":true,"title":"Emergency phone","aliases":["sos","help point","call box"]},
|
||||
"icon-fast_food": {"width":64,"height":64,"x":384,"y":320,"pixelRatio":2,"sdf":true,"title":"Fast food","aliases":["takeaway","burger","snack"]},
|
||||
"icon-fire_station": {"width":64,"height":64,"x":0,"y":384,"pixelRatio":2,"sdf":true,"title":"Fire station","aliases":["fire brigade","fire service","firefighters"]},
|
||||
"icon-florist": {"width":64,"height":64,"x":64,"y":384,"pixelRatio":2,"sdf":true,"title":"Florist","aliases":["flowers","flower shop","bouquet"]},
|
||||
"icon-fountain": {"width":64,"height":64,"x":128,"y":384,"pixelRatio":2,"sdf":true,"title":"Fountain","aliases":["water feature","jet"]},
|
||||
"icon-fuel_pump": {"width":64,"height":64,"x":192,"y":384,"pixelRatio":2,"sdf":true,"title":"Petrol station","aliases":["fuel","gas station","filling station","diesel"]},
|
||||
"icon-furniture": {"width":64,"height":64,"x":256,"y":384,"pixelRatio":2,"sdf":true,"title":"Furniture shop","aliases":["furnishings","home store"]},
|
||||
"icon-garden_center": {"width":64,"height":64,"x":320,"y":384,"pixelRatio":2,"sdf":true,"title":"Garden centre","aliases":["garden_centre","nursery","plants"]},
|
||||
"icon-gift": {"width":64,"height":64,"x":384,"y":384,"pixelRatio":2,"sdf":true,"title":"Gift shop","aliases":["presents","souvenirs"]},
|
||||
"icon-golf": {"width":64,"height":64,"x":448,"y":0,"pixelRatio":2,"sdf":true,"title":"Golf","aliases":["golf course","driving range"]},
|
||||
"icon-greengrocer": {"width":64,"height":64,"x":448,"y":64,"pixelRatio":2,"sdf":true,"title":"Greengrocer","aliases":["fruit","vegetables","produce"]},
|
||||
"icon-hardware": {"width":64,"height":64,"x":448,"y":128,"pixelRatio":2,"sdf":true,"title":"Hardware shop","aliases":["tools","ironmonger"]},
|
||||
"icon-historic": {"width":64,"height":64,"x":448,"y":192,"pixelRatio":2,"sdf":true,"title":"Historic site","aliases":["heritage","ruins","antiquity"]},
|
||||
"icon-hospital": {"width":64,"height":64,"x":448,"y":256,"pixelRatio":2,"sdf":true,"title":"Hospital","aliases":["a&e","emergency room","infirmary","medical"]},
|
||||
"icon-hunting_stand": {"width":64,"height":64,"x":448,"y":320,"pixelRatio":2,"sdf":true,"title":"Hunting stand","aliases":["huntingstand","hide","deer stand"]},
|
||||
"icon-hydrant": {"width":64,"height":64,"x":448,"y":384,"pixelRatio":2,"sdf":true,"title":"Fire hydrant","aliases":["fire plug","water point","firefighting"]},
|
||||
"icon-ice_rink": {"width":64,"height":64,"x":0,"y":448,"pixelRatio":2,"sdf":true,"title":"Ice rink","aliases":["icerink","skating","ice skating"]},
|
||||
"icon-justice": {"width":64,"height":64,"x":64,"y":448,"pixelRatio":2,"sdf":true,"title":"Courthouse","aliases":["court","law court","tribunal","judiciary"]},
|
||||
"icon-khanda": {"width":64,"height":64,"x":128,"y":448,"pixelRatio":2,"sdf":true,"title":"Khanda","aliases":["sikh","sikhism","gurdwara","religion"]},
|
||||
"icon-latin_cross": {"width":64,"height":64,"x":192,"y":448,"pixelRatio":2,"sdf":true,"title":"Latin cross","aliases":["christian","christianity","church","religion"]},
|
||||
"icon-laundry": {"width":64,"height":64,"x":256,"y":448,"pixelRatio":2,"sdf":true,"title":"Laundry","aliases":["launderette","laundromat","washing"]},
|
||||
"icon-library": {"width":64,"height":64,"x":320,"y":448,"pixelRatio":2,"sdf":true,"title":"Library","aliases":["lending","public library","archive"]},
|
||||
"icon-lighthouse": {"width":64,"height":64,"x":384,"y":448,"pixelRatio":2,"sdf":true,"title":"Lighthouse","aliases":["beacon","navigation","coast"]},
|
||||
"icon-lodging": {"width":64,"height":64,"x":448,"y":448,"pixelRatio":2,"sdf":true,"title":"Hotel","aliases":["accommodation","guest house","hostel","motel","b&b"]},
|
||||
"icon-marketplace": {"width":64,"height":64,"x":512,"y":0,"pixelRatio":2,"sdf":true,"title":"Marketplace","aliases":["market","stalls","bazaar"]},
|
||||
"icon-monument": {"width":64,"height":64,"x":512,"y":64,"pixelRatio":2,"sdf":true,"title":"Monument","aliases":["memorial","statue","landmark"]},
|
||||
"icon-newsagent": {"width":64,"height":64,"x":512,"y":128,"pixelRatio":2,"sdf":true,"title":"Newsagent","aliases":["news","tobacconist","corner shop"]},
|
||||
"icon-newspaper": {"width":64,"height":64,"x":512,"y":192,"pixelRatio":2,"sdf":true,"title":"Newspaper kiosk","aliases":["kiosk","newsstand","press"]},
|
||||
"icon-nightclub": {"width":64,"height":64,"x":512,"y":256,"pixelRatio":2,"sdf":true,"title":"Nightclub","aliases":["club","disco","dancing"]},
|
||||
"icon-nursing_home": {"width":64,"height":64,"x":512,"y":320,"pixelRatio":2,"sdf":true,"title":"Nursing home","aliases":["nursinghome","care home","elderly"]},
|
||||
"icon-observation_tower": {"width":64,"height":64,"x":512,"y":384,"pixelRatio":2,"sdf":true,"title":"Observation tower","aliases":["lookout","viewing tower","watchtower"]},
|
||||
"icon-om": {"width":64,"height":64,"x":512,"y":448,"pixelRatio":2,"sdf":true,"title":"Om","aliases":["hindu","hinduism","temple","religion"]},
|
||||
"icon-optician": {"width":64,"height":64,"x":0,"y":512,"pixelRatio":2,"sdf":true,"title":"Optician","aliases":["glasses","eyewear","optometrist"]},
|
||||
"icon-outdoor": {"width":64,"height":64,"x":64,"y":512,"pixelRatio":2,"sdf":true,"title":"Outdoor shop","aliases":["camping shop","hiking","mountaineering"]},
|
||||
"icon-person_kneeling_and_praying": {"width":64,"height":64,"x":128,"y":512,"pixelRatio":2,"sdf":true,"title":"Place of worship","aliases":["place_of_worship","prayer","worship","religion"]},
|
||||
"icon-picnic_site": {"width":64,"height":64,"x":192,"y":512,"pixelRatio":2,"sdf":true,"title":"Picnic site","aliases":["picnic","picnic table","rest area"]},
|
||||
"icon-pill": {"width":64,"height":64,"x":256,"y":512,"pixelRatio":2,"sdf":true,"title":"Pharmacy","aliases":["chemist","drugstore","medicine","prescription"]},
|
||||
"icon-pint_glass": {"width":64,"height":64,"x":320,"y":512,"pixelRatio":2,"sdf":true,"title":"Pub","aliases":["public house","tavern","inn","beer"]},
|
||||
"icon-pitch": {"width":64,"height":64,"x":384,"y":512,"pixelRatio":2,"sdf":true,"title":"Sports pitch","aliases":["field","court","playing field"]},
|
||||
"icon-police_officer": {"width":64,"height":64,"x":448,"y":512,"pixelRatio":2,"sdf":true,"title":"Police","aliases":["police station","law enforcement","constabulary"]},
|
||||
"icon-post": {"width":64,"height":64,"x":512,"y":512,"pixelRatio":2,"sdf":true,"title":"Post office","aliases":["mail","postal","parcel"]},
|
||||
"icon-postbox": {"width":64,"height":64,"x":576,"y":0,"pixelRatio":2,"sdf":true,"title":"Post box","aliases":["mailbox","letter box","pillar box"]},
|
||||
"icon-prison": {"width":64,"height":64,"x":576,"y":64,"pixelRatio":2,"sdf":true,"title":"Prison","aliases":["jail","correctional","penitentiary"]},
|
||||
"icon-rail": {"width":64,"height":64,"x":576,"y":128,"pixelRatio":2,"sdf":true,"title":"Railway","aliases":["train","railway station","metro","subway"]},
|
||||
"icon-recycling": {"width":64,"height":64,"x":576,"y":192,"pixelRatio":2,"sdf":true,"title":"Recycling","aliases":["bottle bank","waste","recycle centre"]},
|
||||
"icon-restaurant": {"width":64,"height":64,"x":576,"y":256,"pixelRatio":2,"sdf":true,"title":"Restaurant","aliases":["dining","eat","food","bistro"]},
|
||||
"icon-restrooms": {"width":64,"height":64,"x":576,"y":320,"pixelRatio":2,"sdf":true,"title":"Toilets","aliases":["toilet","wc","bathroom","lavatory"]},
|
||||
"icon-ring": {"width":64,"height":64,"x":576,"y":384,"pixelRatio":2,"sdf":true,"title":"Jewellery shop","aliases":["jewelry_store","jeweller","jewelry","rings"]},
|
||||
"icon-rocking_horse": {"width":64,"height":64,"x":576,"y":448,"pixelRatio":2,"sdf":true,"title":"Toy shop","aliases":["toys","toy store","games"]},
|
||||
"icon-school": {"width":64,"height":64,"x":576,"y":512,"pixelRatio":2,"sdf":true,"title":"School","aliases":["primary","secondary","education"]},
|
||||
"icon-scissors_and_comb": {"width":64,"height":64,"x":0,"y":576,"pixelRatio":2,"sdf":true,"title":"Hairdresser","aliases":["barber","salon","haircut","hair"]},
|
||||
"icon-seesaw": {"width":64,"height":64,"x":64,"y":576,"pixelRatio":2,"sdf":true,"title":"Playground","aliases":["play area","swings","children"]},
|
||||
"icon-shelter": {"width":64,"height":64,"x":128,"y":576,"pixelRatio":2,"sdf":true,"title":"Shelter","aliases":["bus shelter","refuge","hut"]},
|
||||
"icon-shoes": {"width":64,"height":64,"x":192,"y":576,"pixelRatio":2,"sdf":true,"title":"Shoe shop","aliases":["footwear","cobbler","trainers"]},
|
||||
"icon-shop": {"width":64,"height":64,"x":256,"y":576,"pixelRatio":2,"sdf":true,"title":"Shop","aliases":["store","retail","convenience"]},
|
||||
"icon-shrine": {"width":64,"height":64,"x":320,"y":576,"pixelRatio":2,"sdf":true,"title":"Shrine","aliases":["wayside shrine","sacred","religion"]},
|
||||
"icon-sports": {"width":64,"height":64,"x":384,"y":576,"pixelRatio":2,"sdf":true,"title":"Sports centre","aliases":["leisure centre","gym","fitness"]},
|
||||
"icon-stadium": {"width":64,"height":64,"x":448,"y":576,"pixelRatio":2,"sdf":true,"title":"Stadium","aliases":["arena","ground","sports ground"]},
|
||||
"icon-star_and_crescent": {"width":64,"height":64,"x":512,"y":576,"pixelRatio":2,"sdf":true,"title":"Star and crescent","aliases":["muslim","islam","mosque","religion"]},
|
||||
"icon-star_of_david": {"width":64,"height":64,"x":576,"y":576,"pixelRatio":2,"sdf":true,"title":"Star of David","aliases":["jewish","judaism","synagogue","religion"]},
|
||||
"icon-stationery": {"width":64,"height":64,"x":640,"y":0,"pixelRatio":2,"sdf":true,"title":"Stationery shop","aliases":["office supplies","pens","paper"]},
|
||||
"icon-surveillance": {"width":64,"height":64,"x":640,"y":64,"pixelRatio":2,"sdf":true,"title":"Surveillance camera","aliases":["cctv","camera","security"]},
|
||||
"icon-swimming": {"width":64,"height":64,"x":640,"y":128,"pixelRatio":2,"sdf":true,"title":"Swimming","aliases":["pool","swimming pool","lido","baths"]},
|
||||
"icon-telephone": {"width":64,"height":64,"x":640,"y":192,"pixelRatio":2,"sdf":true,"title":"Telephone","aliases":["phone","call box","payphone"]},
|
||||
"icon-theater": {"width":64,"height":64,"x":640,"y":256,"pixelRatio":2,"sdf":true,"title":"Theatre","aliases":["playhouse","drama","stage","performing arts"]},
|
||||
"icon-town_hall": {"width":64,"height":64,"x":640,"y":320,"pixelRatio":2,"sdf":true,"title":"Town hall","aliases":["city hall","civic","municipal"]},
|
||||
"icon-travel_agent": {"width":64,"height":64,"x":640,"y":384,"pixelRatio":2,"sdf":true,"title":"Travel agent","aliases":["travel agency","holidays","tours"]},
|
||||
"icon-tube_and_toothbrush": {"width":64,"height":64,"x":640,"y":448,"pixelRatio":2,"sdf":true,"title":"Chemist","aliases":["drugstore","toiletries","health and beauty"]},
|
||||
"icon-vending_machine": {"width":64,"height":64,"x":640,"y":512,"pixelRatio":2,"sdf":true,"title":"Vending machine","aliases":["vendingmachine","vending","automat"]},
|
||||
"icon-veterinary": {"width":64,"height":64,"x":640,"y":576,"pixelRatio":2,"sdf":true,"title":"Vet","aliases":["animal hospital","animal clinic","pets"]},
|
||||
"icon-video": {"width":64,"height":64,"x":0,"y":640,"pixelRatio":2,"sdf":true,"title":"Video shop","aliases":["dvd","video rental","movies"]},
|
||||
"icon-viewpoint": {"width":64,"height":64,"x":64,"y":640,"pixelRatio":2,"sdf":true,"title":"Viewpoint","aliases":["lookout","vista","panorama","scenic"]},
|
||||
"icon-waste_basket": {"width":64,"height":64,"x":128,"y":640,"pixelRatio":2,"sdf":true,"title":"Waste basket","aliases":["bin","litter bin","rubbish","trash"]},
|
||||
"icon-wastewater": {"width":64,"height":64,"x":192,"y":640,"pixelRatio":2,"sdf":true,"title":"Wastewater plant","aliases":["sewage","treatment works","sewer"]},
|
||||
"icon-water_park": {"width":64,"height":64,"x":256,"y":640,"pixelRatio":2,"sdf":true,"title":"Water park","aliases":["waterpark","aquapark","slides"]},
|
||||
"icon-watermill": {"width":64,"height":64,"x":320,"y":640,"pixelRatio":2,"sdf":true,"title":"Watermill","aliases":["mill","water wheel"]},
|
||||
"icon-waterworks": {"width":64,"height":64,"x":384,"y":640,"pixelRatio":2,"sdf":true,"title":"Waterworks","aliases":["water treatment","pumping station","water supply"]},
|
||||
"icon-windmill": {"width":64,"height":64,"x":448,"y":640,"pixelRatio":2,"sdf":true,"title":"Windmill","aliases":["mill","wind mill"]},
|
||||
"icon-yin_yang": {"width":64,"height":64,"x":512,"y":640,"pixelRatio":2,"sdf":true,"title":"Yin and yang","aliases":["taoist","taoism","religion","balance"]},
|
||||
"icon-zoo": {"width":64,"height":64,"x":576,"y":640,"pixelRatio":2,"sdf":true,"title":"Zoo","aliases":["animals","wildlife park","safari"]},
|
||||
"marking-oneway": {"width":28,"height":50,"x":704,"y":64,"pixelRatio":2,"sdf":true,"title":"One-way arrow","aliases":["one way","direction","traffic flow"],"center":[0.5,0]},
|
||||
"pattern-hatched": {"width":32,"height":32,"x":732,"y":64,"pixelRatio":2,"sdf":false,"title":"Diagonal hatching","aliases":["hazard","danger area","stripes","fill"]},
|
||||
"pattern-hatched_thin": {"width":32,"height":32,"x":704,"y":114,"pixelRatio":2,"sdf":false,"title":"Fine diagonal hatching","aliases":["hazard","stripes","fill","light"]},
|
||||
"pattern-striped": {"width":32,"height":32,"x":736,"y":114,"pixelRatio":2,"sdf":false,"title":"Horizontal stripes","aliases":["bands","lines","fill"]},
|
||||
"transport-information": {"width":64,"height":64,"x":640,"y":640,"pixelRatio":2,"sdf":true,"title":"Information","aliases":["info","tourist information","help"]},
|
||||
"transport-tram": {"width":64,"height":64,"x":704,"y":0,"pixelRatio":2,"sdf":true,"title":"Tram","aliases":["streetcar","light rail","trolley"]}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 223 KiB |
@@ -69,20 +69,15 @@ export const supportsWebGL2 = (): boolean => {
|
||||
return webGL2Supported;
|
||||
};
|
||||
|
||||
// MapLibre rejects a relative sprite URL. Not the glyph URL: encoding would
|
||||
// mangle its {fontstack} and {range} placeholders.
|
||||
// The demo has no core to proxy through. OSM sets CORS on its tiles but not on
|
||||
// its glyphs and sprites, which is why those come from VersaTiles.
|
||||
// its glyphs, which is why those come from VersaTiles.
|
||||
const DEMO_UPSTREAM = {
|
||||
tilejson: "https://vector.openstreetmap.org/shortbread_v1/tilejson.json",
|
||||
assets: "https://tiles.versatiles.org/assets",
|
||||
glyphs: "https://tiles.versatiles.org/assets/glyphs/{fontstack}/{range}.pbf",
|
||||
};
|
||||
|
||||
const useDemoUpstream = (style: StyleSpecification): StyleSpecification => {
|
||||
style.glyphs = `${DEMO_UPSTREAM.assets}/glyphs/{fontstack}/{range}.pbf`;
|
||||
style.sprite = [
|
||||
{ id: "basics", url: `${DEMO_UPSTREAM.assets}/sprites/basics/sprites` },
|
||||
];
|
||||
style.glyphs = DEMO_UPSTREAM.glyphs;
|
||||
Object.values(style.sources).forEach((source) => {
|
||||
if ("url" in source) {
|
||||
source.url = DEMO_UPSTREAM.tilejson;
|
||||
@@ -91,22 +86,21 @@ const useDemoUpstream = (style: StyleSpecification): StyleSpecification => {
|
||||
return style;
|
||||
};
|
||||
|
||||
// MapLibre rejects a relative sprite URL
|
||||
const absoluteSprite = (url: string) => new URL(url, location.href).href;
|
||||
|
||||
export const loadStyle = async (url: string): Promise<StyleSpecification> => {
|
||||
const style: StyleSpecification = await (await fetch(url)).json();
|
||||
|
||||
if (__DEMO__) {
|
||||
return useDemoUpstream(style);
|
||||
}
|
||||
|
||||
if (typeof style.sprite === "string") {
|
||||
style.sprite = mapTilesUrl(style.sprite);
|
||||
style.sprite = absoluteSprite(style.sprite);
|
||||
} else if (Array.isArray(style.sprite)) {
|
||||
style.sprite = style.sprite.map((sprite) => ({
|
||||
...sprite,
|
||||
url: mapTilesUrl(sprite.url),
|
||||
url: absoluteSprite(sprite.url),
|
||||
}));
|
||||
}
|
||||
return style;
|
||||
return __DEMO__ ? useDemoUpstream(style) : style;
|
||||
};
|
||||
|
||||
// Global to MapLibre, and it throws when set twice.
|
||||
|
||||
@@ -720,14 +720,7 @@ export class HaChartBase extends MobileAwareMixin(LitElement) {
|
||||
// costs the user their place in the tab order, so stay programmatically
|
||||
// focusable for as long as we hold focus, however we stop being sonifiable.
|
||||
this._sonificationFocusHeld = true;
|
||||
// Clicks and taps focus the chart too. Chart2Music only responds to the
|
||||
// keyboard, and once connected it moves the tooltip to the first point, so
|
||||
// pointer focus must not start it.
|
||||
if (
|
||||
this._sonification ||
|
||||
this._sonificationLoading ||
|
||||
!this._chartContainer?.matches(":focus-visible")
|
||||
) {
|
||||
if (this._sonification || this._sonificationLoading) {
|
||||
return;
|
||||
}
|
||||
await this._applyDeferredWork();
|
||||
|
||||
@@ -119,7 +119,11 @@ class HaUserPicker extends LitElement {
|
||||
|
||||
private _getItems = () => this._getUsers(this.users);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | typeof nothing {
|
||||
if (!this.users) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const placeholder =
|
||||
this.placeholder ?? this.hass.localize("ui.components.user-picker.user");
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface AssistPipeline {
|
||||
tts_voice: string | null;
|
||||
wake_word_entity: string | null;
|
||||
wake_word_id: string | null;
|
||||
user_id?: string | null;
|
||||
}
|
||||
|
||||
export interface AssistDevice {
|
||||
@@ -37,6 +38,7 @@ export interface AssistPipelineMutableParams {
|
||||
tts_voice: string | null;
|
||||
wake_word_entity: string | null;
|
||||
wake_word_id: string | null;
|
||||
user_id?: string | null;
|
||||
}
|
||||
|
||||
export interface AssistRunListing {
|
||||
|
||||
+33
@@ -1,8 +1,10 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { LocalizeKeys } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import "../../../../components/user/ha-user-picker";
|
||||
import type { AssistPipeline } from "../../../../data/assist_pipeline";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
|
||||
@@ -80,10 +82,34 @@ export class AssistPipelineDetailConfig extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.computeLabel=${this._computeLabel}
|
||||
></ha-form>
|
||||
<ha-user-picker
|
||||
.hass=${this.hass}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.detail.form.user_id"
|
||||
)}
|
||||
.value=${this.data?.user_id ?? ""}
|
||||
@value-changed=${this._userChanged}
|
||||
></ha-user-picker>
|
||||
<p class="user-description">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.detail.form.user_id_description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _userChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const userId = ev.detail.value || null;
|
||||
if (userId === (this.data?.user_id ?? null)) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.data, user_id: userId },
|
||||
});
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.section {
|
||||
border: 1px solid var(--divider-color);
|
||||
@@ -107,6 +133,13 @@ export class AssistPipelineDetailConfig extends LitElement {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-user-picker {
|
||||
display: block;
|
||||
margin-top: 16px;
|
||||
}
|
||||
p.user-description {
|
||||
margin-top: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ export class DialogVoiceAssistantPipelineDetail extends DirtyStateProviderMixin<
|
||||
.hass=${this.hass}
|
||||
.data=${this._data}
|
||||
.supportedLanguages=${this._supportedLanguages}
|
||||
keys="name,language"
|
||||
keys="name,language,user_id"
|
||||
@value-changed=${this._valueChanged}
|
||||
?autofocus=${!isExistingPipeline}
|
||||
></assist-pipeline-detail-config>
|
||||
@@ -301,6 +301,7 @@ export class DialogVoiceAssistantPipelineDetail extends DirtyStateProviderMixin<
|
||||
tts_voice: data.tts_voice ?? null,
|
||||
wake_word_entity: data.wake_word_entity ?? null,
|
||||
wake_word_id: data.wake_word_id ?? null,
|
||||
user_id: data.user_id ?? null,
|
||||
};
|
||||
if (
|
||||
this._params!.pipeline &&
|
||||
|
||||
@@ -4955,7 +4955,9 @@
|
||||
"tts_language": "[%key:ui::panel::config::voice_assistants::assistants::pipeline::detail::form::language%]",
|
||||
"tts_voice": "Voice",
|
||||
"wake_word_entity": "Wake word engine",
|
||||
"wake_word_id": "Wake word"
|
||||
"wake_word_id": "Wake word",
|
||||
"user_id": "Acts as user",
|
||||
"user_id_description": "Voice requests have no user of their own. Pick one and this assistant speaks for them, so integrations that link a Home Assistant user to an account of their own use the right account."
|
||||
},
|
||||
"steps": {
|
||||
"config": {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @vitest-environment node
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { missingSprites } from "../../build-scripts/gulp/map-sprites.js";
|
||||
|
||||
const STYLE = {
|
||||
layers: [
|
||||
{ id: "poi", type: "symbol", layout: { "icon-image": "base:icon-cafe" } },
|
||||
{
|
||||
id: "poi-amenity",
|
||||
type: "symbol",
|
||||
layout: {
|
||||
"icon-image": [
|
||||
"match",
|
||||
["get", "amenity"],
|
||||
"clinic",
|
||||
"base:icon-hospital",
|
||||
"base:icon-shop",
|
||||
],
|
||||
"text-field": "base:not-an-icon-but-a-label",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "water",
|
||||
type: "fill",
|
||||
paint: { "fill-pattern": "base:pattern-wave" },
|
||||
},
|
||||
{
|
||||
id: "rail",
|
||||
type: "line",
|
||||
paint: {
|
||||
"line-pattern": [
|
||||
"case",
|
||||
["get", "tunnel"],
|
||||
"base:pattern-rail",
|
||||
"base:icon-shop",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "extras",
|
||||
type: "symbol",
|
||||
layout: { "icon-image": "extras:shape-star" },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe("missingSprites", () => {
|
||||
it("reports every base image the sheet lacks, from literals and expressions", () => {
|
||||
expect(
|
||||
missingSprites(STYLE, { "icon-cafe": {}, "icon-shop": {} }).sort()
|
||||
).toEqual(["icon-hospital", "pattern-rail", "pattern-wave"]);
|
||||
});
|
||||
|
||||
it("ignores base-prefixed text and other sprite sheets", () => {
|
||||
expect(
|
||||
missingSprites(STYLE, {
|
||||
"icon-cafe": {},
|
||||
"icon-hospital": {},
|
||||
"icon-shop": {},
|
||||
"pattern-rail": {},
|
||||
"pattern-wave": {},
|
||||
})
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -46,7 +46,7 @@ const STYLE = {
|
||||
version: 8,
|
||||
sources: {},
|
||||
layers: [],
|
||||
sprite: [{ id: "basics", url: "/static/map/sprites/basics/sprites" }],
|
||||
sprite: [{ id: "base", url: "/static/map/sprites/base?v=abc12345" }],
|
||||
};
|
||||
|
||||
const rasterLayer = {
|
||||
@@ -104,6 +104,53 @@ afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("loadStyle", () => {
|
||||
const load = async () =>
|
||||
(await import("../../../src/common/map/base-layer")).loadStyle(
|
||||
"/static/map/light.json"
|
||||
);
|
||||
|
||||
it("makes the bundled sprite URL absolute against this page", async () => {
|
||||
const style = await load();
|
||||
|
||||
expect(style.sprite).toEqual([
|
||||
{
|
||||
id: "base",
|
||||
url: `${location.origin}/static/map/sprites/base?v=abc12345`,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps the bundled sprites in the demo, with tiles and glyphs upstream", async () => {
|
||||
vi.stubGlobal("__DEMO__", true);
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn(async () => ({
|
||||
json: async () => ({
|
||||
...structuredClone(STYLE),
|
||||
glyphs: "/api/map_tiles/fonts/{fontstack}/{range}.pbf",
|
||||
sources: {
|
||||
osm: { type: "vector", url: "/api/map_tiles/tilejson.json" },
|
||||
},
|
||||
}),
|
||||
}))
|
||||
);
|
||||
|
||||
const style = await load();
|
||||
|
||||
expect(style.sprite).toEqual([
|
||||
{
|
||||
id: "base",
|
||||
url: `${location.origin}/static/map/sprites/base?v=abc12345`,
|
||||
},
|
||||
]);
|
||||
expect(style.glyphs).toMatch(/^https:\/\/tiles\.versatiles\.org\//);
|
||||
expect((style.sources.osm as { url: string }).url).toMatch(
|
||||
/^https:\/\/vector\.openstreetmap\.org\//
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createBaseLayer", () => {
|
||||
it("falls back to raster tiles without WebGL2", async () => {
|
||||
const createBaseLayer = await setWebGL2(false);
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import "../../src/components/user/ha-user-picker";
|
||||
import type { User } from "../../src/data/user";
|
||||
import type { HomeAssistant } from "../../src/types";
|
||||
|
||||
const USERS = [
|
||||
{
|
||||
id: "user-firstuser",
|
||||
username: "firstuser",
|
||||
name: "First User",
|
||||
is_owner: false,
|
||||
is_active: true,
|
||||
local_only: false,
|
||||
system_generated: false,
|
||||
group_ids: [],
|
||||
credentials: [],
|
||||
},
|
||||
] as unknown as User[];
|
||||
|
||||
const hassWithUsers = (users: User[]) =>
|
||||
({
|
||||
localize: (key: string) => key,
|
||||
callWS: () => Promise.resolve(users),
|
||||
}) as unknown as HomeAssistant;
|
||||
|
||||
const headlineText = (el: HTMLElement): string => {
|
||||
const texts: string[] = [];
|
||||
const walk = (root: ParentNode) => {
|
||||
for (const node of Array.from(root.querySelectorAll("*"))) {
|
||||
if (node.getAttribute("slot") === "headline") {
|
||||
texts.push(node.textContent?.trim() ?? "");
|
||||
}
|
||||
if (node.shadowRoot) {
|
||||
walk(node.shadowRoot);
|
||||
}
|
||||
}
|
||||
};
|
||||
walk(el.shadowRoot!);
|
||||
return texts.join("|");
|
||||
};
|
||||
|
||||
const tick = () =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
|
||||
// the picker fetches its users, so let its update and that fetch both land
|
||||
const settle = async (el: any) => {
|
||||
await Promise.all([el.updateComplete, tick()]);
|
||||
await Promise.all([el.updateComplete, tick()]);
|
||||
await el.updateComplete;
|
||||
};
|
||||
|
||||
describe("ha-user-picker", () => {
|
||||
beforeAll(() => {
|
||||
// ha-generic-picker asks for it while connecting, jsdom does not provide it
|
||||
window.matchMedia = vi.fn().mockReturnValue({
|
||||
matches: false,
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
}) as any;
|
||||
const internalsProto = window.ElementInternals.prototype as any;
|
||||
internalsProto.setValidity = vi.fn();
|
||||
internalsProto.setFormValue = vi.fn();
|
||||
Object.defineProperty(internalsProto, "validity", {
|
||||
get: () => ({ valid: true }),
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
it("names the user its value refers to", async () => {
|
||||
const el = document.createElement("ha-user-picker") as any;
|
||||
el.hass = hassWithUsers(USERS);
|
||||
el.users = USERS;
|
||||
el.value = "user-firstuser";
|
||||
document.body.appendChild(el);
|
||||
|
||||
await settle(el);
|
||||
|
||||
expect(headlineText(el)).toContain("First User");
|
||||
});
|
||||
|
||||
it("names the user once the fetched list arrives", async () => {
|
||||
// A standalone picker fetches its own users, so it is first asked to render
|
||||
// a value it cannot resolve yet. It must not settle on the raw user id.
|
||||
const el = document.createElement("ha-user-picker") as any;
|
||||
el.hass = hassWithUsers(USERS);
|
||||
el.value = "user-firstuser";
|
||||
document.body.appendChild(el);
|
||||
|
||||
await settle(el);
|
||||
|
||||
expect(headlineText(el)).toContain("First User");
|
||||
expect(headlineText(el)).not.toContain("user-firstuser");
|
||||
});
|
||||
});
|
||||
@@ -3546,7 +3546,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mapbox/jsonlint-lines-primitives@npm:^2.0.2, @mapbox/jsonlint-lines-primitives@npm:~2.0.2":
|
||||
"@mapbox/jsonlint-lines-primitives@npm:^2.0.2, @mapbox/jsonlint-lines-primitives@npm:^2.0.3, @mapbox/jsonlint-lines-primitives@npm:~2.0.2":
|
||||
version: 2.0.3
|
||||
resolution: "@mapbox/jsonlint-lines-primitives@npm:2.0.3"
|
||||
checksum: 10/99404df11b1840153c910154c238f62ba0ea7cfab6aa7ed3bad1e522d31b746bfad78b23e6ee4887196acec76759f1863b5cb4f5e2d95d0dc2a8ea73091c78f6
|
||||
@@ -3644,6 +3644,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@maplibre/maplibre-gl-style-spec@npm:^26.4.4":
|
||||
version: 26.4.4
|
||||
resolution: "@maplibre/maplibre-gl-style-spec@npm:26.4.4"
|
||||
dependencies:
|
||||
"@mapbox/jsonlint-lines-primitives": "npm:^2.0.3"
|
||||
"@mapbox/unitbezier": "npm:^1.0.0"
|
||||
json-stringify-pretty-compact: "npm:^4.0.0"
|
||||
minimist: "npm:^1.2.8"
|
||||
quickselect: "npm:^3.0.0"
|
||||
tinyqueue: "npm:^3.0.0"
|
||||
bin:
|
||||
gl-style-format: dist/gl-style-format.mjs
|
||||
gl-style-migrate: dist/gl-style-migrate.mjs
|
||||
gl-style-validate: dist/gl-style-validate.mjs
|
||||
checksum: 10/c049485af7654f7ffef63cb0ba7afbae231225151fcf0de173f03815e5b3edac5182c94287b0871a77afef0c95537b8d06da6142aa04eecb541430016e368972
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@maplibre/mlt@npm:^1.1.8":
|
||||
version: 1.2.0
|
||||
resolution: "@maplibre/mlt@npm:1.2.0"
|
||||
@@ -6706,12 +6724,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@versatiles/style@npm:5.13.1":
|
||||
version: 5.13.1
|
||||
resolution: "@versatiles/style@npm:5.13.1"
|
||||
"@versatiles/style@npm:6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "@versatiles/style@npm:6.0.1"
|
||||
dependencies:
|
||||
brace-expansion: "npm:^5.0.9"
|
||||
checksum: 10/046be455df89f55bc6a8b1b63a01169f68e701799249761c49523c6098b871d9cdb5b0c8a6a1a15503eee17d89f6fb9f0421eb48cf71d70dfa2cee2900a5b25a
|
||||
"@maplibre/maplibre-gl-style-spec": "npm:^26.4.4"
|
||||
peerDependencies:
|
||||
maplibre-gl: ">=5.0.0"
|
||||
peerDependenciesMeta:
|
||||
maplibre-gl:
|
||||
optional: true
|
||||
checksum: 10/6a4c2c0496c7ab7034eedb91946d60df54a2dbb0b739c86fbb92fa91ac47825434c38892450c0b82282019728ff6f8840b19f3c20d55a67bf70357766040efe2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7655,7 +7678,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"brace-expansion@npm:^5.0.8, brace-expansion@npm:^5.0.9":
|
||||
"brace-expansion@npm:^5.0.8":
|
||||
version: 5.0.9
|
||||
resolution: "brace-expansion@npm:5.0.9"
|
||||
dependencies:
|
||||
@@ -10415,7 +10438,7 @@ __metadata:
|
||||
"@types/sortablejs": "npm:1.15.9"
|
||||
"@types/tar": "npm:7.0.87"
|
||||
"@typescript/native": "npm:[email protected]"
|
||||
"@versatiles/style": "npm:5.13.1"
|
||||
"@versatiles/style": "npm:6.0.1"
|
||||
"@vibrant/color": "npm:4.0.4"
|
||||
"@vitest/coverage-v8": "npm:5.0.2"
|
||||
"@vvo/tzdb": "npm:6.198.0"
|
||||
|
||||
Reference in New Issue
Block a user