diff --git a/.eslintrc.js b/.eslintrc.js
index eaac5c2..e5b7f6f 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,3 +1,6 @@
module.exports = {
- extends: ['./node_modules/@mappable-world/mappable-cli/.eslintrc.js']
+ extends: ['./node_modules/@mappable-world/mappable-cli/.eslintrc.js'],
+ rules: {
+ 'no-console': 'error'
+ }
};
diff --git a/docs/icons.generated.md b/docs/icons.generated.md
new file mode 100644
index 0000000..4f18a46
--- /dev/null
+++ b/docs/icons.generated.md
@@ -0,0 +1,135 @@
+
+
+# List of supported icons
+
+| Name | Normal Size |
+| --------------------- | ---------------------------------------------------------------------- |
+| airfield | ![airfield](../static/icons/airfield_24.svg) |
+| airport | ![airport](../static/icons/airport_24.svg) |
+| animation | ![animation](../static/icons/animation_24.svg) |
+| armenian_church | ![armenian_church](../static/icons/armenian_church_24.svg) |
+| attraction | ![attraction](../static/icons/attraction_24.svg) |
+| auto | ![auto](../static/icons/auto_24.svg) |
+| aviary | ![aviary](../static/icons/aviary_24.svg) |
+| baby_shop | ![baby_shop](../static/icons/baby_shop_24.svg) |
+| banks | ![banks](../static/icons/banks_24.svg) |
+| barbeque | ![barbeque](../static/icons/barbeque_24.svg) |
+| bars | ![bars](../static/icons/bars_24.svg) |
+| beach | ![beach](../static/icons/beach_24.svg) |
+| bench | ![bench](../static/icons/bench_24.svg) |
+| bike | ![bike](../static/icons/bike_24.svg) |
+| bike_rent | ![bike_rent](../static/icons/bike_rent_24.svg) |
+| boat_station | ![boat_station](../static/icons/boat_station_24.svg) |
+| bookstore | ![bookstore](../static/icons/bookstore_24.svg) |
+| buddhism | ![buddhism](../static/icons/buddhism_24.svg) |
+| building | ![building](../static/icons/building_24.svg) |
+| bus | ![bus](../static/icons/bus_24.svg) |
+| cafe | ![cafe](../static/icons/cafe_24.svg) |
+| car_park | ![car_park](../static/icons/car_park_24.svg) |
+| catholic_church | ![catholic_church](../static/icons/catholic_church_24.svg) |
+| cemetery | ![cemetery](../static/icons/cemetery_24.svg) |
+| childrens_playground | ![childrens_playground](../static/icons/childrens_playground_24.svg) |
+| cinemas | ![cinemas](../static/icons/cinemas_24.svg) |
+| clothes_shop | ![clothes_shop](../static/icons/clothes_shop_24.svg) |
+| college | ![college](../static/icons/college_24.svg) |
+| concert_hall | ![concert_hall](../static/icons/concert_hall_24.svg) |
+| confectionary | ![confectionary](../static/icons/confectionary_24.svg) |
+| currency_exchange | ![currency_exchange](../static/icons/currency_exchange_24.svg) |
+| dental | ![dental](../static/icons/dental_24.svg) |
+| driving_school | ![driving_school](../static/icons/driving_school_24.svg) |
+| drugstores | ![drugstores](../static/icons/drugstores_24.svg) |
+| dry_cleaning | ![dry_cleaning](../static/icons/dry_cleaning_24.svg) |
+| equestrian | ![equestrian](../static/icons/equestrian_24.svg) |
+| fallback | ![fallback](../static/icons/fallback_24.svg) |
+| fast_food | ![fast_food](../static/icons/fast_food_24.svg) |
+| festival | ![festival](../static/icons/festival_24.svg) |
+| film_studio | ![film_studio](../static/icons/film_studio_24.svg) |
+| fire_station | ![fire_station](../static/icons/fire_station_24.svg) |
+| fitness | ![fitness](../static/icons/fitness_24.svg) |
+| flower_shop | ![flower_shop](../static/icons/flower_shop_24.svg) |
+| forest | ![forest](../static/icons/forest_24.svg) |
+| fountain | ![fountain](../static/icons/fountain_24.svg) |
+| furniture_store | ![furniture_store](../static/icons/furniture_store_24.svg) |
+| garden | ![garden](../static/icons/garden_24.svg) |
+| gasstation | ![gasstation](../static/icons/gasstation_24.svg) |
+| government | ![government](../static/icons/government_24.svg) |
+| hairdressers | ![hairdressers](../static/icons/hairdressers_24.svg) |
+| haulier | ![haulier](../static/icons/haulier_24.svg) |
+| helicopter | ![helicopter](../static/icons/helicopter_24.svg) |
+| hospital | ![hospital](../static/icons/hospital_24.svg) |
+| hotels | ![hotels](../static/icons/hotels_24.svg) |
+| hypermarket | ![hypermarket](../static/icons/hypermarket_24.svg) |
+| industrial_enterprise | ![industrial_enterprise](../static/icons/industrial_enterprise_24.svg) |
+| information | ![information](../static/icons/information_24.svg) |
+| kindergarten | ![kindergarten](../static/icons/kindergarten_24.svg) |
+| landmark | ![landmark](../static/icons/landmark_24.svg) |
+| laundry | ![laundry](../static/icons/laundry_24.svg) |
+| library | ![library](../static/icons/library_24.svg) |
+| malls | ![malls](../static/icons/malls_24.svg) |
+| medicine | ![medicine](../static/icons/medicine_24.svg) |
+| memorable_event | ![memorable_event](../static/icons/memorable_event_24.svg) |
+| metro | ![metro](../static/icons/metro_24.svg) |
+| metro_bus | ![metro_bus](../static/icons/metro_bus_24.svg) |
+| metro_cable | ![metro_cable](../static/icons/metro_cable_24.svg) |
+| metro_entrance | ![metro_entrance](../static/icons/metro_entrance_24.svg) |
+| metro_funicular | ![metro_funicular](../static/icons/metro_funicular_24.svg) |
+| metro_light | ![metro_light](../static/icons/metro_light_24.svg) |
+| metro_monorail | ![metro_monorail](../static/icons/metro_monorail_24.svg) |
+| metro_tram | ![metro_tram](../static/icons/metro_tram_24.svg) |
+| mobile_phones | ![mobile_phones](../static/icons/mobile_phones_24.svg) |
+| money_coin | ![money_coin](../static/icons/money_coin_24.svg) |
+| monument | ![monument](../static/icons/monument_24.svg) |
+| mosque | ![mosque](../static/icons/mosque_24.svg) |
+| mountain | ![mountain](../static/icons/mountain_24.svg) |
+| museum | ![museum](../static/icons/museum_24.svg) |
+| nail_studio | ![nail_studio](../static/icons/nail_studio_24.svg) |
+| office | ![office](../static/icons/office_24.svg) |
+| office_service | ![office_service](../static/icons/office_service_24.svg) |
+| orthodox_church | ![orthodox_church](../static/icons/orthodox_church_24.svg) |
+| park | ![park](../static/icons/park_24.svg) |
+| pavilion | ![pavilion](../static/icons/pavilion_24.svg) |
+| pet_playground | ![pet_playground](../static/icons/pet_playground_24.svg) |
+| petshop | ![petshop](../static/icons/petshop_24.svg) |
+| photo | ![photo](../static/icons/photo_24.svg) |
+| picnic | ![picnic](../static/icons/picnic_24.svg) |
+| pier | ![pier](../static/icons/pier_24.svg) |
+| playground | ![playground](../static/icons/playground_24.svg) |
+| police | ![police](../static/icons/police_24.svg) |
+| police_post | ![police_post](../static/icons/police_post_24.svg) |
+| port | ![port](../static/icons/port_24.svg) |
+| post_office | ![post_office](../static/icons/post_office_24.svg) |
+| printing_services | ![printing_services](../static/icons/printing_services_24.svg) |
+| protestant_church | ![protestant_church](../static/icons/protestant_church_24.svg) |
+| racing | ![racing](../static/icons/racing_24.svg) |
+| railway | ![railway](../static/icons/railway_24.svg) |
+| railway_station | ![railway_station](../static/icons/railway_station_24.svg) |
+| recycling | ![recycling](../static/icons/recycling_24.svg) |
+| restaurants | ![restaurants](../static/icons/restaurants_24.svg) |
+| rezervation | ![rezervation](../static/icons/rezervation_24.svg) |
+| sanatorium | ![sanatorium](../static/icons/sanatorium_24.svg) |
+| science | ![science](../static/icons/science_24.svg) |
+| skating_rink | ![skating_rink](../static/icons/skating_rink_24.svg) |
+| software | ![software](../static/icons/software_24.svg) |
+| spa | ![spa](../static/icons/spa_24.svg) |
+| sportcenter | ![sportcenter](../static/icons/sportcenter_24.svg) |
+| spring | ![spring](../static/icons/spring_24.svg) |
+| stadium | ![stadium](../static/icons/stadium_24.svg) |
+| stage | ![stage](../static/icons/stage_24.svg) |
+| stenograffia | ![stenograffia](../static/icons/stenograffia_24.svg) |
+| supermarket | ![supermarket](../static/icons/supermarket_24.svg) |
+| sushi | ![sushi](../static/icons/sushi_24.svg) |
+| swimming_pool | ![swimming_pool](../static/icons/swimming_pool_24.svg) |
+| synagogue | ![synagogue](../static/icons/synagogue_24.svg) |
+| tailor | ![tailor](../static/icons/tailor_24.svg) |
+| taxi | ![taxi](../static/icons/taxi_24.svg) |
+| theatre | ![theatre](../static/icons/theatre_24.svg) |
+| ticket_office | ![ticket_office](../static/icons/ticket_office_24.svg) |
+| tire_fitting | ![tire_fitting](../static/icons/tire_fitting_24.svg) |
+| tram | ![tram](../static/icons/tram_24.svg) |
+| trash | ![trash](../static/icons/trash_24.svg) |
+| travel_agency | ![travel_agency](../static/icons/travel_agency_24.svg) |
+| viewpoint | ![viewpoint](../static/icons/viewpoint_24.svg) |
+| waterfall | ![waterfall](../static/icons/waterfall_24.svg) |
+| waterpark | ![waterpark](../static/icons/waterpark_24.svg) |
+| wc | ![wc](../static/icons/wc_24.svg) |
+| zoo | ![zoo](../static/icons/zoo_24.svg) |
diff --git a/example/default-markers/common.css b/example/default-markers/common.css
new file mode 100644
index 0000000..e69de29
diff --git a/example/default-markers/common.ts b/example/default-markers/common.ts
new file mode 100644
index 0000000..146a531
--- /dev/null
+++ b/example/default-markers/common.ts
@@ -0,0 +1,45 @@
+import type {LngLat, LngLatBounds, MMapLocationRequest} from '@mappable-world/mappable-types';
+import {MMapDefaultMarkerProps} from '../../src';
+
+const BOUNDS: LngLatBounds = [
+ [54.58311, 25.9985],
+ [56.30248, 24.47889]
+];
+
+export const LOCATION: MMapLocationRequest = {bounds: BOUNDS};
+
+const CENTER: LngLat = [(BOUNDS[0][0] + BOUNDS[1][0]) / 2, (BOUNDS[0][1] + BOUNDS[1][1]) / 2];
+const STEP = 0.3;
+
+const getCoordinates = (row: number, col: number): LngLat => [CENTER[0] + row * STEP, CENTER[1] + col * STEP];
+
+export const MARKER_LOCATIONS: MMapDefaultMarkerProps[] = [
+ // default marker
+ {coordinates: getCoordinates(-3, 0.5), size: 'normal'},
+ {coordinates: getCoordinates(-3, 0), size: 'small'},
+ {coordinates: getCoordinates(-3, -0.5), size: 'micro'},
+ // fallback color marker
+ {coordinates: getCoordinates(-2, 0.5), size: 'normal', color: 'bluebell',iconName:'fallback'},
+ {coordinates: getCoordinates(-2, 0), size: 'small', color: 'bluebell',iconName:'fallback'},
+ {coordinates: getCoordinates(-2, -0.5), size: 'micro', color: 'bluebell',iconName:'fallback'},
+ // color icon marker
+ {coordinates: getCoordinates(-1, 0.5), size: 'normal', color: 'ceil', iconName: 'attraction'},
+ {coordinates: getCoordinates(-1, 0), size: 'small', color: 'ceil', iconName: 'attraction'},
+ {coordinates: getCoordinates(-1, -0.5), size: 'micro', color: 'ceil', iconName: 'attraction'},
+ // title hint
+ {coordinates: getCoordinates(0, 0.5), size: 'normal', color: 'darksalmon', iconName: 'restaurants',title:'Normal title'},
+ {coordinates: getCoordinates(0, 0), size: 'small', color: 'darksalmon', iconName: 'restaurants',title:'Normal title'},
+ {coordinates: getCoordinates(0, -0.5), size: 'micro', color: 'darksalmon', iconName: 'restaurants',title:'Normal title'},
+ // title subtitle hint
+ {coordinates: getCoordinates(1, 0.5), size: 'normal', color: 'green', iconName: 'beach',title:'Normal title',subtitle:'Normal subtitle'},
+ {coordinates: getCoordinates(1, 0), size: 'small', color: 'green', iconName: 'beach',title:'Normal title',subtitle:'Normal subtitle'},
+ {coordinates: getCoordinates(1, -0.5), size: 'micro', color: 'green', iconName: 'beach',title:'Normal title',subtitle:'Normal subtitle'},
+ // hover hint
+ {coordinates: getCoordinates(2, 0.5), size: 'normal', color: "pink", iconName: 'medicine',title:'Hover title',subtitle:'Hover subtitle',staticHint:false,},
+ {coordinates: getCoordinates(2, 0), size: 'small', color: "pink", iconName: 'medicine',title:'Hover title',subtitle:'Hover subtitle',staticHint:false,},
+ {coordinates: getCoordinates(2, -0.5), size: 'micro', color: "pink", iconName: 'medicine',title:'Hover title',subtitle:'Hover subtitle',staticHint:false,},
+ // overflow hint
+ {coordinates: getCoordinates(3, 0.5), size: 'normal', color: "orchid", iconName: 'auto',title:'Overflow title Overflow title',subtitle:'Overflow subtitle Overflow subtitle'},
+ {coordinates: getCoordinates(3, 0), size: 'small', color: "orchid", iconName: 'auto',title:'Overflow title Overflow title',subtitle:'Overflow subtitle Overflow subtitle'},
+ {coordinates: getCoordinates(3, -0.5), size: 'micro', color: "orchid", iconName: 'auto',title:'Overflow title Overflow title',subtitle:'Overflow subtitle Overflow subtitle'},
+];
diff --git a/example/default-markers/react/index.html b/example/default-markers/react/index.html
new file mode 100644
index 0000000..4183912
--- /dev/null
+++ b/example/default-markers/react/index.html
@@ -0,0 +1,37 @@
+
+
+
+ React example mappable-default-ui-theme
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/default-markers/react/index.tsx b/example/default-markers/react/index.tsx
new file mode 100644
index 0000000..d1d47e9
--- /dev/null
+++ b/example/default-markers/react/index.tsx
@@ -0,0 +1,46 @@
+import {LOCATION, MARKER_LOCATIONS} from '../common';
+import {MMapTheme} from '@mappable-world/mappable-types';
+
+window.map = null;
+
+main();
+async function main() {
+ const [mappableReact] = await Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]);
+ const reactify = mappableReact.reactify.bindTo(React, ReactDOM);
+
+ const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapControls, MMapControlButton} =
+ reactify.module(mappable);
+
+ const {useState, useCallback} = React;
+
+ const {MMapDefaultMarker} = reactify.module(await mappable.import('@mappable-world/mappable-default-ui-theme'));
+
+ ReactDOM.render(
+
+
+ ,
+ document.getElementById('app')
+ );
+
+ function App() {
+ const [location] = useState(LOCATION);
+ const [theme, setTheme] = useState('light');
+
+ const switchTheme = useCallback(() => {
+ setTheme(theme === 'light' ? 'dark' : 'light');
+ }, [theme]);
+
+ return (
+ (map = x)}>
+
+
+
+
+
+ {MARKER_LOCATIONS.map((props, i) => (
+
+ ))}
+
+ );
+ }
+}
diff --git a/example/default-markers/vanilla/index.html b/example/default-markers/vanilla/index.html
new file mode 100644
index 0000000..730390e
--- /dev/null
+++ b/example/default-markers/vanilla/index.html
@@ -0,0 +1,35 @@
+
+
+
+ Vanilla example mappable-default-ui-theme
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/default-markers/vanilla/index.ts b/example/default-markers/vanilla/index.ts
new file mode 100644
index 0000000..e74c136
--- /dev/null
+++ b/example/default-markers/vanilla/index.ts
@@ -0,0 +1,29 @@
+import {LOCATION, MARKER_LOCATIONS} from '../common';
+window.map = null;
+
+main();
+async function main() {
+ await mappable.ready;
+ const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapControls, MMapControlButton} = mappable;
+
+ const {MMapDefaultMarker} = await mappable.import('@mappable-world/mappable-default-ui-theme');
+
+ map = new MMap(document.getElementById('app'), {location: LOCATION});
+
+ map.addChild(new MMapDefaultSchemeLayer({}));
+ map.addChild(new MMapDefaultFeaturesLayer({}));
+
+ map.addChild(
+ new MMapControls({position: 'top right'}).addChild(
+ new MMapControlButton({
+ text: 'Switch theme',
+ onClick: () => {
+ const {theme} = map;
+ map.update({theme: theme === 'light' ? 'dark' : 'light'});
+ }
+ })
+ )
+ );
+
+ MARKER_LOCATIONS.forEach((props) => map.addChild(new MMapDefaultMarker(props)));
+}
diff --git a/example/default-markers/vue/index.html b/example/default-markers/vue/index.html
new file mode 100644
index 0000000..85eeebd
--- /dev/null
+++ b/example/default-markers/vue/index.html
@@ -0,0 +1,36 @@
+
+
+
+ Vue example mappable-default-ui-theme
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/default-markers/vue/index.ts b/example/default-markers/vue/index.ts
new file mode 100644
index 0000000..9c1157e
--- /dev/null
+++ b/example/default-markers/vue/index.ts
@@ -0,0 +1,47 @@
+import {MMapTheme} from '@mappable-world/mappable-types';
+import {LOCATION, MARKER_LOCATIONS} from '../common';
+
+window.map = null;
+
+main();
+async function main() {
+ const [mappableVue] = await Promise.all([mappable.import('@mappable-world/mappable-vuefy'), mappable.ready]);
+ const vuefy = mappableVue.vuefy.bindTo(Vue);
+
+ const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapControls, MMapControlButton} =
+ vuefy.module(mappable);
+
+ const {MMapDefaultMarker} = vuefy.module(await mappable.import('@mappable-world/mappable-default-ui-theme'));
+
+ const app = Vue.createApp({
+ components: {
+ MMap,
+ MMapDefaultSchemeLayer,
+ MMapDefaultFeaturesLayer,
+ MMapDefaultMarker,
+ MMapControls,
+ MMapControlButton
+ },
+ setup() {
+ const refMap = (ref: any) => {
+ window.map = ref?.entity;
+ };
+ const theme = Vue.ref('light');
+
+ const switchTheme = () => {
+ theme.value = theme.value === 'light' ? 'dark' : 'light';
+ };
+ return {LOCATION, refMap, MARKER_LOCATIONS, theme, switchTheme};
+ },
+ template: `
+
+
+
+
+
+
+
+ `
+ });
+ app.mount('#app');
+}
diff --git a/example/tsconfig.json b/example/tsconfig.json
index 2a6357c..28b0012 100644
--- a/example/tsconfig.json
+++ b/example/tsconfig.json
@@ -2,8 +2,9 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"strict": false,
+ "moduleResolution": "Node16",
"rootDirs": ["./", "../"],
- "types": ["./types.d.ts", "../types/index.d.ts"]
+ "types": ["../types/index.d.ts"]
},
"include": ["./**/*.ts", "./**/*.tsx"]
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index 3ff122b..9eb7d64 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"@types/got": "9.6.12",
"@types/jest": "29.5.3",
"@types/jsdom": "21.1.1",
+ "@types/lodash": "^4.17.0",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"@typescript-eslint/eslint-plugin": "6.0.0",
@@ -24,17 +25,21 @@
"eslint": "8.44.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-prettier": "4.2.1",
- "got": "11.8.6",
+ "figma-api": "^1.11.0",
+ "got": "^11.8.6",
"html-webpack-plugin": "^5.5.3",
"identity-obj-proxy": "3.0.0",
"jest": "29.6.1",
"jsdom": "22.1.0",
+ "lodash": "^4.17.21",
+ "nanospinner": "^1.1.0",
"prettier": "3.0.0",
"style-loader": "3.3.3",
"svgo": "^3.2.0",
"terser-webpack-plugin": "5.3.9",
"ts-jest": "29.1.1",
"ts-loader": "9.4.4",
+ "ts-node": "^10.9.2",
"typescript": "5.1.6",
"vue": "^3.4.21",
"webpack": "5.88.1",
@@ -713,6 +718,28 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -1398,6 +1425,30 @@
"node": ">=10.13.0"
}
},
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1646,6 +1697,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/lodash": {
+ "version": "4.17.0",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
+ "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
+ "dev": true
+ },
"node_modules/@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@@ -2353,6 +2410,15 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/acorn-walk": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -2505,6 +2571,12 @@
"node": ">= 8"
}
},
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -2532,6 +2604,15 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
+ "node_modules/axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"node_modules/babel-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -3256,6 +3337,12 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
@@ -3592,6 +3679,15 @@
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
"dev": true
},
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -4360,6 +4456,22 @@
"bser": "2.1.1"
}
},
+ "node_modules/figma-api": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/figma-api/-/figma-api-1.11.0.tgz",
+ "integrity": "sha512-inGRug909pPeLqcCcjMwXGnxcJjMVeAXk/kLLjlo2y/IjYURgX56u7HUqUrmASmSUqQB9BVuz/PlK9KRDWkiPA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "12.0.2",
+ "axios": "^0.21.1"
+ }
+ },
+ "node_modules/figma-api/node_modules/@types/node": {
+ "version": "12.0.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
+ "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
+ "dev": true
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -6501,6 +6613,15 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/nanospinner": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/nanospinner/-/nanospinner-1.1.0.tgz",
+ "integrity": "sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==",
+ "dev": true,
+ "dependencies": {
+ "picocolors": "^1.0.0"
+ }
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -8549,6 +8670,49 @@
"webpack": "^5.0.0"
}
},
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@@ -8717,6 +8881,12 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
"node_modules/v8-to-istanbul": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
@@ -9329,6 +9499,15 @@
"node": ">=12"
}
},
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -9852,6 +10031,27 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "dependencies": {
+ "@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "requires": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ }
+ }
+ },
"@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@@ -10371,6 +10571,30 @@
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
"dev": true
},
+ "@tsconfig/node10": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true
+ },
"@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -10619,6 +10843,12 @@
"@types/node": "*"
}
},
+ "@types/lodash": {
+ "version": "4.17.0",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
+ "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
+ "dev": true
+ },
"@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
@@ -11192,6 +11422,12 @@
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true
},
+ "acorn-walk": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+ "dev": true
+ },
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -11296,6 +11532,12 @@
"picomatch": "^2.0.4"
}
},
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -11320,6 +11562,15 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
+ "axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "dev": true,
+ "requires": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
"babel-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -11873,6 +12124,12 @@
"prompts": "^2.0.1"
}
},
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
"cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
@@ -12109,6 +12366,12 @@
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
"dev": true
},
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
"diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -12694,6 +12957,24 @@
"bser": "2.1.1"
}
},
+ "figma-api": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/figma-api/-/figma-api-1.11.0.tgz",
+ "integrity": "sha512-inGRug909pPeLqcCcjMwXGnxcJjMVeAXk/kLLjlo2y/IjYURgX56u7HUqUrmASmSUqQB9BVuz/PlK9KRDWkiPA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "12.0.2",
+ "axios": "^0.21.1"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "12.0.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
+ "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
+ "dev": true
+ }
+ }
+ },
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -14280,6 +14561,15 @@
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true
},
+ "nanospinner": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/nanospinner/-/nanospinner-1.1.0.tgz",
+ "integrity": "sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==",
+ "dev": true,
+ "requires": {
+ "picocolors": "^1.0.0"
+ }
+ },
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -15773,6 +16063,27 @@
"semver": "^7.3.4"
}
},
+ "ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ }
+ },
"tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@@ -15887,6 +16198,12 @@
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
+ "v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
"v8-to-istanbul": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
@@ -16317,6 +16634,12 @@
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true
},
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true
+ },
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index c1f2ca6..4e3c9db 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,10 @@
"watch": "webpack --watch",
"start": "webpack serve",
"bump": "npm version prerelease --preid=beta --no-git-tag-version && npm run bump:git",
- "bump:git": "git add --all && git commit -m \"New version $npm_package_version\" && git tag $npm_package_version && git push --tags origin HEAD:main"
+ "bump:git": "git add --all && git commit -m \"New version $npm_package_version\" && git tag $npm_package_version && git push --tags origin HEAD:main",
+ "sync-figma": "npm run sync-icons && npm run sync-colors",
+ "sync-icons": "node -r dotenv/config -r ts-node/register ./tools/scripts/sync-icons.ts",
+ "sync-colors": "node -r dotenv/config -r ts-node/register ./tools/scripts/sync-colors.ts"
},
"devDependencies": {
"@mappable-world/mappable-cli": "^0.0.32",
@@ -23,6 +26,7 @@
"@types/got": "9.6.12",
"@types/jest": "29.5.3",
"@types/jsdom": "21.1.1",
+ "@types/lodash": "^4.17.0",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"@typescript-eslint/eslint-plugin": "6.0.0",
@@ -33,17 +37,21 @@
"eslint": "8.44.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-prettier": "4.2.1",
- "got": "11.8.6",
+ "figma-api": "^1.11.0",
+ "got": "^11.8.6",
"html-webpack-plugin": "^5.5.3",
"identity-obj-proxy": "3.0.0",
"jest": "29.6.1",
"jsdom": "22.1.0",
+ "lodash": "^4.17.21",
+ "nanospinner": "^1.1.0",
"prettier": "3.0.0",
"style-loader": "3.3.3",
"svgo": "^3.2.0",
"terser-webpack-plugin": "5.3.9",
"ts-jest": "29.1.1",
"ts-loader": "9.4.4",
+ "ts-node": "^10.9.2",
"typescript": "5.1.6",
"vue": "^3.4.21",
"webpack": "5.88.1",
diff --git a/src/icons/icon-colors.generated.ts b/src/icons/icon-colors.generated.ts
new file mode 100644
index 0000000..b2b9e33
--- /dev/null
+++ b/src/icons/icon-colors.generated.ts
@@ -0,0 +1,13 @@
+/** Don't edit manually only color names. Generated by script: ./tools/icons/generate-colors.ts */
+export const iconColors = {
+ darkgray: {day: '#ada9a6ff', night: '#6f737aff'},
+ pink: {day: '#ff8f96ff', night: '#b96066ff'},
+ seawave: {day: '#62c0c6ff', night: '#468286ff'},
+ orchid: {day: '#e096d0ff', night: '#916187ff'},
+ steelblue: {day: '#498ea5ff', night: '#57a8c2ff'},
+ bluebell: {day: '#9d9dc4ff', night: '#6767a3ff'},
+ ceil: {day: '#88aecfff', night: '#537695ff'},
+ green: {day: '#5ebd8cff', night: '#468c68ff'},
+ darksalmon: {day: '#f09a75ff', night: '#ab6f55ff'}
+} as const;
+export type IconColor = keyof typeof iconColors;
diff --git a/src/icons/icon-name.generated.ts b/src/icons/icon-name.generated.ts
new file mode 100644
index 0000000..141e0c7
--- /dev/null
+++ b/src/icons/icon-name.generated.ts
@@ -0,0 +1,131 @@
+/** Don't edit manually. Generated by script: ./tools/icons/generate-types.ts */
+export type IconName =
+ | 'airfield'
+ | 'airport'
+ | 'animation'
+ | 'armenian_church'
+ | 'attraction'
+ | 'auto'
+ | 'aviary'
+ | 'baby_shop'
+ | 'banks'
+ | 'barbeque'
+ | 'bars'
+ | 'beach'
+ | 'bench'
+ | 'bike'
+ | 'bike_rent'
+ | 'boat_station'
+ | 'bookstore'
+ | 'buddhism'
+ | 'building'
+ | 'bus'
+ | 'cafe'
+ | 'car_park'
+ | 'catholic_church'
+ | 'cemetery'
+ | 'childrens_playground'
+ | 'cinemas'
+ | 'clothes_shop'
+ | 'college'
+ | 'concert_hall'
+ | 'confectionary'
+ | 'currency_exchange'
+ | 'dental'
+ | 'driving_school'
+ | 'drugstores'
+ | 'dry_cleaning'
+ | 'equestrian'
+ | 'fallback'
+ | 'fast_food'
+ | 'festival'
+ | 'film_studio'
+ | 'fire_station'
+ | 'fitness'
+ | 'flower_shop'
+ | 'forest'
+ | 'fountain'
+ | 'furniture_store'
+ | 'garden'
+ | 'gasstation'
+ | 'government'
+ | 'hairdressers'
+ | 'haulier'
+ | 'helicopter'
+ | 'hospital'
+ | 'hotels'
+ | 'hypermarket'
+ | 'industrial_enterprise'
+ | 'information'
+ | 'kindergarten'
+ | 'landmark'
+ | 'laundry'
+ | 'library'
+ | 'malls'
+ | 'medicine'
+ | 'memorable_event'
+ | 'metro'
+ | 'metro_bus'
+ | 'metro_cable'
+ | 'metro_entrance'
+ | 'metro_funicular'
+ | 'metro_light'
+ | 'metro_monorail'
+ | 'metro_tram'
+ | 'mobile_phones'
+ | 'money_coin'
+ | 'monument'
+ | 'mosque'
+ | 'mountain'
+ | 'museum'
+ | 'nail_studio'
+ | 'office'
+ | 'office_service'
+ | 'orthodox_church'
+ | 'park'
+ | 'pavilion'
+ | 'pet_playground'
+ | 'petshop'
+ | 'photo'
+ | 'picnic'
+ | 'pier'
+ | 'playground'
+ | 'police'
+ | 'police_post'
+ | 'port'
+ | 'post_office'
+ | 'printing_services'
+ | 'protestant_church'
+ | 'racing'
+ | 'railway'
+ | 'railway_station'
+ | 'recycling'
+ | 'restaurants'
+ | 'rezervation'
+ | 'sanatorium'
+ | 'science'
+ | 'skating_rink'
+ | 'software'
+ | 'spa'
+ | 'sportcenter'
+ | 'spring'
+ | 'stadium'
+ | 'stage'
+ | 'stenograffia'
+ | 'supermarket'
+ | 'sushi'
+ | 'swimming_pool'
+ | 'synagogue'
+ | 'tailor'
+ | 'taxi'
+ | 'theatre'
+ | 'ticket_office'
+ | 'tire_fitting'
+ | 'tram'
+ | 'trash'
+ | 'travel_agency'
+ | 'viewpoint'
+ | 'waterfall'
+ | 'waterpark'
+ | 'wc'
+ | 'zoo';
diff --git a/src/icons/icons.generated.ts b/src/icons/icons.generated.ts
new file mode 100644
index 0000000..c7f5ea4
--- /dev/null
+++ b/src/icons/icons.generated.ts
@@ -0,0 +1,263 @@
+/** Don't edit manually. Generated by script: ./tools/icons/generate-imports.ts */
+import airfield_24 from '../../static/icons/airfield_24.svg';
+import airport_24 from '../../static/icons/airport_24.svg';
+import animation_24 from '../../static/icons/animation_24.svg';
+import armenian_church_24 from '../../static/icons/armenian_church_24.svg';
+import attraction_24 from '../../static/icons/attraction_24.svg';
+import auto_24 from '../../static/icons/auto_24.svg';
+import aviary_24 from '../../static/icons/aviary_24.svg';
+import baby_shop_24 from '../../static/icons/baby_shop_24.svg';
+import banks_24 from '../../static/icons/banks_24.svg';
+import barbeque_24 from '../../static/icons/barbeque_24.svg';
+import bars_24 from '../../static/icons/bars_24.svg';
+import beach_24 from '../../static/icons/beach_24.svg';
+import bench_24 from '../../static/icons/bench_24.svg';
+import bike_24 from '../../static/icons/bike_24.svg';
+import bike_rent_24 from '../../static/icons/bike_rent_24.svg';
+import boat_station_24 from '../../static/icons/boat_station_24.svg';
+import bookstore_24 from '../../static/icons/bookstore_24.svg';
+import buddhism_24 from '../../static/icons/buddhism_24.svg';
+import building_24 from '../../static/icons/building_24.svg';
+import bus_24 from '../../static/icons/bus_24.svg';
+import cafe_24 from '../../static/icons/cafe_24.svg';
+import car_park_24 from '../../static/icons/car_park_24.svg';
+import catholic_church_24 from '../../static/icons/catholic_church_24.svg';
+import cemetery_24 from '../../static/icons/cemetery_24.svg';
+import childrens_playground_24 from '../../static/icons/childrens_playground_24.svg';
+import cinemas_24 from '../../static/icons/cinemas_24.svg';
+import clothes_shop_24 from '../../static/icons/clothes_shop_24.svg';
+import college_24 from '../../static/icons/college_24.svg';
+import concert_hall_24 from '../../static/icons/concert_hall_24.svg';
+import confectionary_24 from '../../static/icons/confectionary_24.svg';
+import currency_exchange_24 from '../../static/icons/currency_exchange_24.svg';
+import dental_24 from '../../static/icons/dental_24.svg';
+import driving_school_24 from '../../static/icons/driving_school_24.svg';
+import drugstores_24 from '../../static/icons/drugstores_24.svg';
+import dry_cleaning_24 from '../../static/icons/dry_cleaning_24.svg';
+import equestrian_24 from '../../static/icons/equestrian_24.svg';
+import fallback_24 from '../../static/icons/fallback_24.svg';
+import fast_food_24 from '../../static/icons/fast_food_24.svg';
+import festival_24 from '../../static/icons/festival_24.svg';
+import film_studio_24 from '../../static/icons/film_studio_24.svg';
+import fire_station_24 from '../../static/icons/fire_station_24.svg';
+import fitness_24 from '../../static/icons/fitness_24.svg';
+import flower_shop_24 from '../../static/icons/flower_shop_24.svg';
+import forest_24 from '../../static/icons/forest_24.svg';
+import fountain_24 from '../../static/icons/fountain_24.svg';
+import furniture_store_24 from '../../static/icons/furniture_store_24.svg';
+import garden_24 from '../../static/icons/garden_24.svg';
+import gasstation_24 from '../../static/icons/gasstation_24.svg';
+import government_24 from '../../static/icons/government_24.svg';
+import hairdressers_24 from '../../static/icons/hairdressers_24.svg';
+import haulier_24 from '../../static/icons/haulier_24.svg';
+import helicopter_24 from '../../static/icons/helicopter_24.svg';
+import hospital_24 from '../../static/icons/hospital_24.svg';
+import hotels_24 from '../../static/icons/hotels_24.svg';
+import hypermarket_24 from '../../static/icons/hypermarket_24.svg';
+import industrial_enterprise_24 from '../../static/icons/industrial_enterprise_24.svg';
+import information_24 from '../../static/icons/information_24.svg';
+import kindergarten_24 from '../../static/icons/kindergarten_24.svg';
+import landmark_24 from '../../static/icons/landmark_24.svg';
+import laundry_24 from '../../static/icons/laundry_24.svg';
+import library_24 from '../../static/icons/library_24.svg';
+import malls_24 from '../../static/icons/malls_24.svg';
+import medicine_24 from '../../static/icons/medicine_24.svg';
+import memorable_event_24 from '../../static/icons/memorable_event_24.svg';
+import metro_24 from '../../static/icons/metro_24.svg';
+import metro_bus_24 from '../../static/icons/metro_bus_24.svg';
+import metro_cable_24 from '../../static/icons/metro_cable_24.svg';
+import metro_entrance_24 from '../../static/icons/metro_entrance_24.svg';
+import metro_funicular_24 from '../../static/icons/metro_funicular_24.svg';
+import metro_light_24 from '../../static/icons/metro_light_24.svg';
+import metro_monorail_24 from '../../static/icons/metro_monorail_24.svg';
+import metro_tram_24 from '../../static/icons/metro_tram_24.svg';
+import mobile_phones_24 from '../../static/icons/mobile_phones_24.svg';
+import money_coin_24 from '../../static/icons/money_coin_24.svg';
+import monument_24 from '../../static/icons/monument_24.svg';
+import mosque_24 from '../../static/icons/mosque_24.svg';
+import mountain_24 from '../../static/icons/mountain_24.svg';
+import museum_24 from '../../static/icons/museum_24.svg';
+import nail_studio_24 from '../../static/icons/nail_studio_24.svg';
+import office_24 from '../../static/icons/office_24.svg';
+import office_service_24 from '../../static/icons/office_service_24.svg';
+import orthodox_church_24 from '../../static/icons/orthodox_church_24.svg';
+import park_24 from '../../static/icons/park_24.svg';
+import pavilion_24 from '../../static/icons/pavilion_24.svg';
+import pet_playground_24 from '../../static/icons/pet_playground_24.svg';
+import petshop_24 from '../../static/icons/petshop_24.svg';
+import photo_24 from '../../static/icons/photo_24.svg';
+import picnic_24 from '../../static/icons/picnic_24.svg';
+import pier_24 from '../../static/icons/pier_24.svg';
+import playground_24 from '../../static/icons/playground_24.svg';
+import police_24 from '../../static/icons/police_24.svg';
+import police_post_24 from '../../static/icons/police_post_24.svg';
+import port_24 from '../../static/icons/port_24.svg';
+import post_office_24 from '../../static/icons/post_office_24.svg';
+import printing_services_24 from '../../static/icons/printing_services_24.svg';
+import protestant_church_24 from '../../static/icons/protestant_church_24.svg';
+import racing_24 from '../../static/icons/racing_24.svg';
+import railway_24 from '../../static/icons/railway_24.svg';
+import railway_station_24 from '../../static/icons/railway_station_24.svg';
+import recycling_24 from '../../static/icons/recycling_24.svg';
+import restaurants_24 from '../../static/icons/restaurants_24.svg';
+import rezervation_24 from '../../static/icons/rezervation_24.svg';
+import sanatorium_24 from '../../static/icons/sanatorium_24.svg';
+import science_24 from '../../static/icons/science_24.svg';
+import skating_rink_24 from '../../static/icons/skating_rink_24.svg';
+import software_24 from '../../static/icons/software_24.svg';
+import spa_24 from '../../static/icons/spa_24.svg';
+import sportcenter_24 from '../../static/icons/sportcenter_24.svg';
+import spring_24 from '../../static/icons/spring_24.svg';
+import stadium_24 from '../../static/icons/stadium_24.svg';
+import stage_24 from '../../static/icons/stage_24.svg';
+import stenograffia_24 from '../../static/icons/stenograffia_24.svg';
+import supermarket_24 from '../../static/icons/supermarket_24.svg';
+import sushi_24 from '../../static/icons/sushi_24.svg';
+import swimming_pool_24 from '../../static/icons/swimming_pool_24.svg';
+import synagogue_24 from '../../static/icons/synagogue_24.svg';
+import tailor_24 from '../../static/icons/tailor_24.svg';
+import taxi_24 from '../../static/icons/taxi_24.svg';
+import theatre_24 from '../../static/icons/theatre_24.svg';
+import ticket_office_24 from '../../static/icons/ticket_office_24.svg';
+import tire_fitting_24 from '../../static/icons/tire_fitting_24.svg';
+import tram_24 from '../../static/icons/tram_24.svg';
+import trash_24 from '../../static/icons/trash_24.svg';
+import travel_agency_24 from '../../static/icons/travel_agency_24.svg';
+import viewpoint_24 from '../../static/icons/viewpoint_24.svg';
+import waterfall_24 from '../../static/icons/waterfall_24.svg';
+import waterpark_24 from '../../static/icons/waterpark_24.svg';
+import wc_24 from '../../static/icons/wc_24.svg';
+import zoo_24 from '../../static/icons/zoo_24.svg';
+
+import type {Icons} from './types';
+export const icons: Icons = {
+ airfield: airfield_24,
+ airport: airport_24,
+ animation: animation_24,
+ armenian_church: armenian_church_24,
+ attraction: attraction_24,
+ auto: auto_24,
+ aviary: aviary_24,
+ baby_shop: baby_shop_24,
+ banks: banks_24,
+ barbeque: barbeque_24,
+ bars: bars_24,
+ beach: beach_24,
+ bench: bench_24,
+ bike: bike_24,
+ bike_rent: bike_rent_24,
+ boat_station: boat_station_24,
+ bookstore: bookstore_24,
+ buddhism: buddhism_24,
+ building: building_24,
+ bus: bus_24,
+ cafe: cafe_24,
+ car_park: car_park_24,
+ catholic_church: catholic_church_24,
+ cemetery: cemetery_24,
+ childrens_playground: childrens_playground_24,
+ cinemas: cinemas_24,
+ clothes_shop: clothes_shop_24,
+ college: college_24,
+ concert_hall: concert_hall_24,
+ confectionary: confectionary_24,
+ currency_exchange: currency_exchange_24,
+ dental: dental_24,
+ driving_school: driving_school_24,
+ drugstores: drugstores_24,
+ dry_cleaning: dry_cleaning_24,
+ equestrian: equestrian_24,
+ fallback: fallback_24,
+ fast_food: fast_food_24,
+ festival: festival_24,
+ film_studio: film_studio_24,
+ fire_station: fire_station_24,
+ fitness: fitness_24,
+ flower_shop: flower_shop_24,
+ forest: forest_24,
+ fountain: fountain_24,
+ furniture_store: furniture_store_24,
+ garden: garden_24,
+ gasstation: gasstation_24,
+ government: government_24,
+ hairdressers: hairdressers_24,
+ haulier: haulier_24,
+ helicopter: helicopter_24,
+ hospital: hospital_24,
+ hotels: hotels_24,
+ hypermarket: hypermarket_24,
+ industrial_enterprise: industrial_enterprise_24,
+ information: information_24,
+ kindergarten: kindergarten_24,
+ landmark: landmark_24,
+ laundry: laundry_24,
+ library: library_24,
+ malls: malls_24,
+ medicine: medicine_24,
+ memorable_event: memorable_event_24,
+ metro: metro_24,
+ metro_bus: metro_bus_24,
+ metro_cable: metro_cable_24,
+ metro_entrance: metro_entrance_24,
+ metro_funicular: metro_funicular_24,
+ metro_light: metro_light_24,
+ metro_monorail: metro_monorail_24,
+ metro_tram: metro_tram_24,
+ mobile_phones: mobile_phones_24,
+ money_coin: money_coin_24,
+ monument: monument_24,
+ mosque: mosque_24,
+ mountain: mountain_24,
+ museum: museum_24,
+ nail_studio: nail_studio_24,
+ office: office_24,
+ office_service: office_service_24,
+ orthodox_church: orthodox_church_24,
+ park: park_24,
+ pavilion: pavilion_24,
+ pet_playground: pet_playground_24,
+ petshop: petshop_24,
+ photo: photo_24,
+ picnic: picnic_24,
+ pier: pier_24,
+ playground: playground_24,
+ police: police_24,
+ police_post: police_post_24,
+ port: port_24,
+ post_office: post_office_24,
+ printing_services: printing_services_24,
+ protestant_church: protestant_church_24,
+ racing: racing_24,
+ railway: railway_24,
+ railway_station: railway_station_24,
+ recycling: recycling_24,
+ restaurants: restaurants_24,
+ rezervation: rezervation_24,
+ sanatorium: sanatorium_24,
+ science: science_24,
+ skating_rink: skating_rink_24,
+ software: software_24,
+ spa: spa_24,
+ sportcenter: sportcenter_24,
+ spring: spring_24,
+ stadium: stadium_24,
+ stage: stage_24,
+ stenograffia: stenograffia_24,
+ supermarket: supermarket_24,
+ sushi: sushi_24,
+ swimming_pool: swimming_pool_24,
+ synagogue: synagogue_24,
+ tailor: tailor_24,
+ taxi: taxi_24,
+ theatre: theatre_24,
+ ticket_office: ticket_office_24,
+ tire_fitting: tire_fitting_24,
+ tram: tram_24,
+ trash: trash_24,
+ travel_agency: travel_agency_24,
+ viewpoint: viewpoint_24,
+ waterfall: waterfall_24,
+ waterpark: waterpark_24,
+ wc: wc_24,
+ zoo: zoo_24
+};
diff --git a/src/icons/index.ts b/src/icons/index.ts
new file mode 100644
index 0000000..b536d5c
--- /dev/null
+++ b/src/icons/index.ts
@@ -0,0 +1,3 @@
+export {IconColor, iconColors} from './icon-colors.generated';
+export {IconName} from './icon-name.generated';
+export {icons} from './icons.generated';
diff --git a/src/icons/types.ts b/src/icons/types.ts
new file mode 100644
index 0000000..a6e7657
--- /dev/null
+++ b/src/icons/types.ts
@@ -0,0 +1,5 @@
+import {IconName} from './icon-name.generated';
+
+export type Icons = {
+ [key in IconName]: string | null;
+};
diff --git a/src/index.ts b/src/index.ts
index 995436d..b4b1dad 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1 +1,2 @@
export * from './controls';
+export * from './markers';
diff --git a/src/internal/internal.d.ts b/src/internal/internal.d.ts
new file mode 100644
index 0000000..44350b3
--- /dev/null
+++ b/src/internal/internal.d.ts
@@ -0,0 +1,4 @@
+declare module '*.svg' {
+ const content: string;
+ export default content;
+}
diff --git a/src/markers/MMapDefaultMarker/backgrounds/micro-poi-stroke.svg b/src/markers/MMapDefaultMarker/backgrounds/micro-poi-stroke.svg
new file mode 100644
index 0000000..09648f8
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/micro-poi-stroke.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/backgrounds/micro-poi.svg b/src/markers/MMapDefaultMarker/backgrounds/micro-poi.svg
new file mode 100644
index 0000000..503e318
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/micro-poi.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/backgrounds/normal-pin-stroke.svg b/src/markers/MMapDefaultMarker/backgrounds/normal-pin-stroke.svg
new file mode 100644
index 0000000..1c98d05
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/normal-pin-stroke.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/backgrounds/normal-pin.svg b/src/markers/MMapDefaultMarker/backgrounds/normal-pin.svg
new file mode 100644
index 0000000..833776d
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/normal-pin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/backgrounds/small-poi-stroke.svg b/src/markers/MMapDefaultMarker/backgrounds/small-poi-stroke.svg
new file mode 100644
index 0000000..5eb676d
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/small-poi-stroke.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/backgrounds/small-poi.svg b/src/markers/MMapDefaultMarker/backgrounds/small-poi.svg
new file mode 100644
index 0000000..834e8e6
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/backgrounds/small-poi.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/markers/MMapDefaultMarker/index.css b/src/markers/MMapDefaultMarker/index.css
new file mode 100644
index 0000000..94157dd
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/index.css
@@ -0,0 +1,133 @@
+@keyframes mappable--default-marker-hint-hover {
+ from {
+ margin-left: -10px;
+ opacity: 0;
+ }
+ to {
+ margin-left: 0px;
+ opacity: 1;
+ }
+}
+
+.mappable--default-marker-point {
+ position: absolute;
+ cursor: pointer;
+}
+.mappable--default-marker-point svg {
+ display: block;
+}
+
+.mappable--hint {
+ box-sizing: border-box;
+ position: absolute;
+ max-width: 190px;
+ padding: 4px 8px;
+ flex-direction: column;
+ border-radius: 8px;
+ background: rgba(255, 255, 255, 0.84);
+ line-height: 16px;
+ white-space: nowrap;
+ z-index: -2;
+}
+.mappable--hint__stable {
+ display: inline-flex;
+}
+.mappable--hint__hovered {
+ display: none;
+}
+.mappable--default-marker-point:hover .mappable--hint__hovered {
+ display: inline-flex;
+ animation: mappable--default-marker-hint-hover 200ms ease-out;
+}
+.mappable--hint-title {
+ display: block;
+ width: 100%;
+ color: #050d33;
+ font-size: 14px;
+ font-weight: 500;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.mappable--hint-subtitle {
+ display: block;
+ width: 100%;
+ color: #7b7d85;
+ font-size: 12px;
+ font-weight: 400;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+/* normal size */
+.mappable--pin .mappable--default-marker__background {
+ position: absolute;
+ transform: translate(-50%, calc(-100% + 2px)); /* 2px - point radius */
+ filter: drop-shadow(0px 2px 6px rgba(24, 27, 34, 0.4));
+}
+.mappable--pin .mappable--default-marker__stroke {
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: -1;
+}
+.mappable--pin .mappable--default-marker__icon {
+ position: absolute;
+ transform: translate(-50%, calc(-59px + 2px + 10px)); /* 59px - pin height, 2px - point radius, 10px - offset */
+ z-index: 1;
+}
+.mappable--pin .mappable--hint {
+ transform: translate(
+ calc(44px / 2 + 5px),
+ calc(-59px + 2px + 10px)
+ ); /* 44px, 59px - pin width, height, 2px - point radius, 5px, 10px - offsets */
+}
+
+/* small size */
+.mappable--small-poi .mappable--default-marker__background {
+ position: absolute;
+ transform: translate(-50%, -50%);
+}
+.mappable--small-poi .mappable--default-marker__stroke {
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: -1;
+ -webkit-filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.1));
+ filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.1));
+}
+.mappable--small-poi .mappable--default-marker__icon {
+ position: absolute;
+ z-index: 1;
+ transform: translate(-50%, -50%);
+}
+.mappable--small-poi .mappable--default-marker__icon svg {
+ transform: scale(calc(14 / 24));
+}
+.mappable--small-poi .mappable--hint {
+ transform: translate(calc(24px / 2 + 4px), calc(-24px / 2)); /* 24px - poi size, 4px offset */
+}
+
+/* micro size */
+.mappable--micro-poi .mappable--default-marker__background {
+ position: absolute;
+ transform: translate(-50%, -50%);
+}
+.mappable--micro-poi .mappable--default-marker__stroke {
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: -1;
+ -webkit-filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.1));
+ filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.1));
+}
+.mappable--micro-poi .mappable--hint {
+ transform: translate(calc(14px / 2 + 8px), calc(-14px / 2 - 4px));
+}
+
+/* dark theme */
+.mappable--default-marker-point_dark .mappable--hint {
+ background: rgba(29, 30, 31, 0.84);
+}
+.mappable--default-marker-point_dark .mappable--hint-title {
+ color: #f2f5fa;
+}
+.mappable--default-marker-point_dark .mappable--hint-subtitle {
+ color: #7b7d85;
+}
diff --git a/src/markers/MMapDefaultMarker/index.ts b/src/markers/MMapDefaultMarker/index.ts
new file mode 100644
index 0000000..fcad78e
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/index.ts
@@ -0,0 +1,298 @@
+import {MMapMarker, MMapMarkerProps} from '@mappable-world/mappable-types';
+import {IconColor, IconName, iconColors, icons} from '../../icons';
+import {MMapDefaultMarkerVuefyOptions} from './vue';
+
+import microPoiStrokeSVG from './backgrounds/micro-poi-stroke.svg';
+import microPoiSVG from './backgrounds/micro-poi.svg';
+import normalPinStrokeSVG from './backgrounds/normal-pin-stroke.svg';
+import normalPinSVG from './backgrounds/normal-pin.svg';
+import smallPoiStrokeSVG from './backgrounds/small-poi-stroke.svg';
+import smallPoiSVG from './backgrounds/small-poi.svg';
+
+import './index.css';
+
+const GLYPH_COLOR = '#FFFFFF';
+
+const MARKER_BASE_CLASS = 'mappable--default-marker-point';
+const MARKER_BASE_DARK_CLASS = 'mappable--default-marker-point_dark';
+
+const NORMAL_SIZE_MARKER_CLASS = 'mappable--pin';
+const SMALL_SIZE_MARKER_CLASS = 'mappable--small-poi';
+const MICRO_SIZE_MARKER_CLASS = 'mappable--micro-poi';
+
+const BACKGROUND_CLASS = 'mappable--default-marker__background';
+const STROKE_CLASS = 'mappable--default-marker__stroke';
+const ICON_CLASS = 'mappable--default-marker__icon';
+
+const HINT_CLASS = 'mappable--hint';
+const HINT_TITLE_CLASS = 'mappable--hint-title';
+const HINT_SUBTITLE_CLASS = 'mappable--hint-subtitle';
+const HINT_STABLE = 'mappable--hint__stable';
+const HINT_HOVERED = 'mappable--hint__hovered';
+
+export type ThemesColor = {day: string; night: string};
+export type MarkerColorProps = IconColor | ThemesColor;
+export type MarkerSizeProps = 'normal' | 'small' | 'micro';
+
+export type MMapDefaultMarkerProps = MMapMarkerProps & {
+ iconName?: IconName;
+ color?: MarkerColorProps;
+ size?: MarkerSizeProps;
+ title?: string;
+ subtitle?: string;
+ staticHint?: boolean;
+};
+
+const defaultProps = Object.freeze({color: 'darkgray', size: 'small', staticHint: true});
+type DefaultProps = typeof defaultProps;
+
+type BackgroundAndIcon = {background: HTMLElement; stroke: HTMLElement; icon: HTMLElement};
+
+export class MMapDefaultMarker extends mappable.MMapComplexEntity {
+ static defaultProps = defaultProps;
+ static [mappable.optionsKeyVuefy] = MMapDefaultMarkerVuefyOptions;
+
+ private _marker: MMapMarker;
+ private _markerElement: HTMLElement;
+
+ private _color: ThemesColor;
+ private _background: HTMLElement;
+ private _stroke?: HTMLElement;
+ private _icon?: HTMLElement;
+
+ private _hintContainer: HTMLElement;
+ private _titleHint: HTMLElement;
+ private _subtitleHint: HTMLElement;
+
+ constructor(props: MMapDefaultMarkerProps) {
+ super(props);
+ }
+
+ protected _onAttach(): void {
+ this._color = this._getColor();
+
+ const {size, title, subtitle} = this._props;
+
+ this._markerElement = document.createElement('mappable');
+ this._markerElement.classList.add(MARKER_BASE_CLASS);
+ this._updateMarkerSize();
+
+ switch (size) {
+ case 'normal':
+ const normal = this._createNormalPin();
+ this._icon = normal.icon;
+ this._background = normal.background;
+ this._stroke = normal.stroke;
+ break;
+ case 'small':
+ const small = this._createSmallPoi();
+ this._icon = small.icon;
+ this._background = small.background;
+ this._stroke = small.stroke;
+ break;
+ case 'micro':
+ const micro = this._createMicroPoi();
+ this._stroke = micro.stroke;
+ this._background = micro.background;
+ this._icon = micro.icon;
+ break;
+ default:
+ throw new Error(
+ 'Unknown size has been specified. The following sizes are available: normal, small and micro.'
+ );
+ }
+
+ this._markerElement.appendChild(this._background);
+ if (this._stroke) {
+ this._markerElement.appendChild(this._stroke);
+ }
+ if (this._icon) {
+ this._markerElement.appendChild(this._icon);
+ }
+
+ this._hintContainer = this._createHintContainer();
+ if (title || subtitle) {
+ this._markerElement.appendChild(this._hintContainer);
+ }
+
+ this._marker = new mappable.MMapMarker(this._props, this._markerElement);
+ this.addChild(this._marker);
+
+ this._watchContext(mappable.ThemeContext, () => this._updateTheme(), {
+ immediate: true
+ });
+ }
+
+ protected _onUpdate(propsDiff: Partial): void {
+ const {title, subtitle} = this._props;
+ if (propsDiff.color !== undefined) {
+ this._color = this._getColor();
+ this._updateTheme();
+ }
+ if (propsDiff.size !== undefined) {
+ this._updateMarkerSize();
+ this._updateSVG();
+ }
+
+ this._titleHint.textContent = title ?? '';
+ this._subtitleHint.textContent = subtitle ?? '';
+ const hintAttached = this._markerElement.contains(this._hintContainer);
+ if (!hintAttached && (title !== undefined || subtitle !== undefined)) {
+ this._markerElement.appendChild(this._hintContainer);
+ } else if (hintAttached && title === undefined && subtitle === undefined) {
+ this._markerElement.removeChild(this._hintContainer);
+ }
+
+ if (propsDiff.staticHint !== undefined) {
+ this._hintContainer.classList.toggle(HINT_STABLE, this._props.staticHint);
+ this._hintContainer.classList.toggle(HINT_HOVERED, !this._props.staticHint);
+ }
+
+ this._marker.update(this._props);
+ }
+
+ private _createHintContainer(): HTMLElement {
+ const {title, subtitle, staticHint} = this._props;
+ const hintContainer = document.createElement('mappable');
+ this._titleHint = document.createElement('mappable');
+ this._subtitleHint = document.createElement('mappable');
+
+ hintContainer.classList.add(HINT_CLASS);
+ hintContainer.classList.add(staticHint ? HINT_STABLE : HINT_HOVERED);
+ this._titleHint.classList.add(HINT_TITLE_CLASS);
+ this._subtitleHint.classList.add(HINT_SUBTITLE_CLASS);
+
+ this._titleHint.textContent = title ?? '';
+ this._subtitleHint.textContent = subtitle ?? '';
+
+ hintContainer.appendChild(this._titleHint);
+ hintContainer.appendChild(this._subtitleHint);
+ return hintContainer;
+ }
+
+ private _updateTheme() {
+ const themeCtx = this._consumeContext(mappable.ThemeContext);
+ const theme = themeCtx.theme;
+
+ const strokeColor = GLYPH_COLOR;
+ const backgroundColor = theme === 'light' ? this._color.day : this._color.night;
+ this._markerElement.classList.toggle(MARKER_BASE_DARK_CLASS, theme === 'dark');
+
+ switch (this._props.size) {
+ case 'normal':
+ this._background.style.color = backgroundColor;
+ this._stroke.style.color = strokeColor;
+ this._icon.style.color = strokeColor;
+ break;
+ case 'small':
+ this._background.style.color = backgroundColor;
+ this._stroke.style.color = strokeColor;
+ this._icon.style.color = strokeColor;
+ break;
+ case 'micro':
+ this._background.style.color = backgroundColor;
+ this._stroke.style.color = strokeColor;
+ break;
+ }
+ }
+
+ private _updateMarkerSize() {
+ const {size} = this._props;
+ this._markerElement.classList.toggle(NORMAL_SIZE_MARKER_CLASS, size === 'normal');
+ this._markerElement.classList.toggle(SMALL_SIZE_MARKER_CLASS, size === 'small');
+ this._markerElement.classList.toggle(MICRO_SIZE_MARKER_CLASS, size === 'micro');
+ }
+
+ private _updateSVG() {
+ const {size} = this._props;
+ this._icon.innerHTML = this._getIcon();
+ switch (size) {
+ case 'normal':
+ this._background.innerHTML = normalPinSVG;
+ this._stroke.innerHTML = normalPinStrokeSVG;
+ break;
+ case 'small':
+ this._background.innerHTML = smallPoiSVG;
+ this._stroke.innerHTML = smallPoiStrokeSVG;
+ break;
+ case 'micro':
+ this._background.innerHTML = microPoiSVG;
+ this._stroke.innerHTML = microPoiStrokeSVG;
+ break;
+ }
+ }
+
+ private _getIcon(): string {
+ const {size} = this._props;
+ if (size === 'micro' || this._props.iconName === undefined) {
+ return '';
+ }
+
+ return icons[this._props.iconName];
+ }
+
+ private _getColor(): ThemesColor {
+ const color = this._props.color as MarkerColorProps;
+
+ if (typeof color === 'string') {
+ if (!iconColors[color]) {
+ throw new Error(
+ 'The color should be one of the available color presets. If you need a custom color, pass it as an object with fields for day and night.'
+ );
+ }
+ return iconColors[color];
+ }
+
+ return color;
+ }
+
+ private _createNormalPin(): BackgroundAndIcon {
+ const normalPin = document.createElement('mappable');
+ const normalPinStroke = document.createElement('mappable');
+ const normalIcon = document.createElement('mappable');
+
+ normalPin.classList.add(BACKGROUND_CLASS);
+ normalPin.innerHTML = normalPinSVG;
+
+ normalPinStroke.classList.add(STROKE_CLASS);
+ normalPinStroke.innerHTML = normalPinStrokeSVG;
+
+ normalIcon.classList.add(ICON_CLASS);
+ normalIcon.innerHTML = this._getIcon();
+
+ return {background: normalPin, icon: normalIcon, stroke: normalPinStroke};
+ }
+
+ private _createSmallPoi(): BackgroundAndIcon {
+ const smallPoi = document.createElement('mappable');
+ const smallPoiStroke = document.createElement('mappable');
+ const smallIcon = document.createElement('mappable');
+
+ smallPoi.classList.add(BACKGROUND_CLASS);
+ smallPoi.innerHTML = smallPoiSVG;
+
+ smallPoiStroke.classList.add(STROKE_CLASS);
+ smallPoiStroke.innerHTML = smallPoiStrokeSVG;
+
+ smallIcon.classList.add(ICON_CLASS);
+ smallIcon.innerHTML = this._getIcon();
+
+ return {background: smallPoi, icon: smallIcon, stroke: smallPoiStroke};
+ }
+
+ private _createMicroPoi(): BackgroundAndIcon {
+ const microPoi = document.createElement('mappable');
+ const microPoiStroke = document.createElement('mappable');
+ const microIcon = document.createElement('mappable');
+
+ microPoi.classList.add(BACKGROUND_CLASS);
+ microPoi.innerHTML = microPoiSVG;
+
+ microPoiStroke.classList.add(STROKE_CLASS);
+ microPoiStroke.innerHTML = microPoiStrokeSVG;
+
+ microIcon.classList.add(ICON_CLASS);
+
+ return {background: microPoi, stroke: microPoiStroke, icon: microIcon};
+ }
+}
diff --git a/src/markers/MMapDefaultMarker/vue/index.ts b/src/markers/MMapDefaultMarker/vue/index.ts
new file mode 100644
index 0000000..c72bcdf
--- /dev/null
+++ b/src/markers/MMapDefaultMarker/vue/index.ts
@@ -0,0 +1,33 @@
+import {CustomVuefyOptions} from '@mappable-world/mappable-types/modules/vuefy';
+import type TVue from '@vue/runtime-core';
+import {MMapDefaultMarker, MarkerColorProps, MarkerSizeProps} from '../';
+import {MMapFeatureProps, MMapMarkerEventHandler} from '@mappable-world/mappable-types';
+import {IconName} from '../../../icons';
+
+export const MMapDefaultMarkerVuefyOptions: CustomVuefyOptions = {
+ props: {
+ coordinates: {type: Object, required: true},
+ source: String,
+ zIndex: {type: Number, default: 0},
+ properties: Object,
+ id: String,
+ disableRoundCoordinates: {type: Boolean, default: undefined},
+ hideOutsideViewport: {type: [Object, Boolean], default: false},
+ draggable: {type: Boolean, default: false},
+ mapFollowsOnDrag: {type: [Boolean, Object]},
+ onDragStart: Function as TVue.PropType,
+ onDragEnd: Function as TVue.PropType,
+ onDragMove: Function as TVue.PropType,
+ blockEvents: {type: Boolean, default: undefined},
+ blockBehaviors: {type: Boolean, default: undefined},
+ onDoubleClick: Function as TVue.PropType,
+ onClick: Function as TVue.PropType,
+ onFastClick: Function as TVue.PropType,
+ iconName: {type: String as TVue.PropType},
+ color: {type: Object as TVue.PropType, default: 'darkgray'},
+ size: {type: String as TVue.PropType, default: 'small'},
+ title: {type: String},
+ subtitle: {type: String},
+ staticHint: {type: Boolean, default: true}
+ }
+};
diff --git a/src/markers/index.ts b/src/markers/index.ts
new file mode 100644
index 0000000..8ad99ac
--- /dev/null
+++ b/src/markers/index.ts
@@ -0,0 +1 @@
+export * from './MMapDefaultMarker';
diff --git a/static/icons/airfield_24.svg b/static/icons/airfield_24.svg
new file mode 100644
index 0000000..19f3b2a
--- /dev/null
+++ b/static/icons/airfield_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/airport_24.svg b/static/icons/airport_24.svg
new file mode 100644
index 0000000..7c6839c
--- /dev/null
+++ b/static/icons/airport_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/animation_24.svg b/static/icons/animation_24.svg
new file mode 100644
index 0000000..5af7796
--- /dev/null
+++ b/static/icons/animation_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/armenian_church_24.svg b/static/icons/armenian_church_24.svg
new file mode 100644
index 0000000..e96115b
--- /dev/null
+++ b/static/icons/armenian_church_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/attraction_24.svg b/static/icons/attraction_24.svg
new file mode 100644
index 0000000..ef7f352
--- /dev/null
+++ b/static/icons/attraction_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/auto_24.svg b/static/icons/auto_24.svg
new file mode 100644
index 0000000..8737805
--- /dev/null
+++ b/static/icons/auto_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/aviary_24.svg b/static/icons/aviary_24.svg
new file mode 100644
index 0000000..0c2d2d6
--- /dev/null
+++ b/static/icons/aviary_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/baby_shop_24.svg b/static/icons/baby_shop_24.svg
new file mode 100644
index 0000000..9786799
--- /dev/null
+++ b/static/icons/baby_shop_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/banks_24.svg b/static/icons/banks_24.svg
new file mode 100644
index 0000000..2bba9b3
--- /dev/null
+++ b/static/icons/banks_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/barbeque_24.svg b/static/icons/barbeque_24.svg
new file mode 100644
index 0000000..588774e
--- /dev/null
+++ b/static/icons/barbeque_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bars_24.svg b/static/icons/bars_24.svg
new file mode 100644
index 0000000..1d7cd89
--- /dev/null
+++ b/static/icons/bars_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/beach_24.svg b/static/icons/beach_24.svg
new file mode 100644
index 0000000..1a1465e
--- /dev/null
+++ b/static/icons/beach_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bench_24.svg b/static/icons/bench_24.svg
new file mode 100644
index 0000000..7e6b868
--- /dev/null
+++ b/static/icons/bench_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bike_24.svg b/static/icons/bike_24.svg
new file mode 100644
index 0000000..f184f37
--- /dev/null
+++ b/static/icons/bike_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bike_rent_24.svg b/static/icons/bike_rent_24.svg
new file mode 100644
index 0000000..f184f37
--- /dev/null
+++ b/static/icons/bike_rent_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/boat_station_24.svg b/static/icons/boat_station_24.svg
new file mode 100644
index 0000000..31331ca
--- /dev/null
+++ b/static/icons/boat_station_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bookstore_24.svg b/static/icons/bookstore_24.svg
new file mode 100644
index 0000000..cfd40e0
--- /dev/null
+++ b/static/icons/bookstore_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/buddhism_24.svg b/static/icons/buddhism_24.svg
new file mode 100644
index 0000000..807816c
--- /dev/null
+++ b/static/icons/buddhism_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/building_24.svg b/static/icons/building_24.svg
new file mode 100644
index 0000000..4cdeddd
--- /dev/null
+++ b/static/icons/building_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/bus_24.svg b/static/icons/bus_24.svg
new file mode 100644
index 0000000..7c0d81c
--- /dev/null
+++ b/static/icons/bus_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/cafe_24.svg b/static/icons/cafe_24.svg
new file mode 100644
index 0000000..a27232b
--- /dev/null
+++ b/static/icons/cafe_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/car_park_24.svg b/static/icons/car_park_24.svg
new file mode 100644
index 0000000..fb00be2
--- /dev/null
+++ b/static/icons/car_park_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/catholic_church_24.svg b/static/icons/catholic_church_24.svg
new file mode 100644
index 0000000..e96115b
--- /dev/null
+++ b/static/icons/catholic_church_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/cemetery_24.svg b/static/icons/cemetery_24.svg
new file mode 100644
index 0000000..cbe44d8
--- /dev/null
+++ b/static/icons/cemetery_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/childrens_playground_24.svg b/static/icons/childrens_playground_24.svg
new file mode 100644
index 0000000..63cfc32
--- /dev/null
+++ b/static/icons/childrens_playground_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/cinemas_24.svg b/static/icons/cinemas_24.svg
new file mode 100644
index 0000000..e5cd208
--- /dev/null
+++ b/static/icons/cinemas_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/clothes_shop_24.svg b/static/icons/clothes_shop_24.svg
new file mode 100644
index 0000000..bbaf91d
--- /dev/null
+++ b/static/icons/clothes_shop_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/college_24.svg b/static/icons/college_24.svg
new file mode 100644
index 0000000..9769b47
--- /dev/null
+++ b/static/icons/college_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/concert_hall_24.svg b/static/icons/concert_hall_24.svg
new file mode 100644
index 0000000..1061df7
--- /dev/null
+++ b/static/icons/concert_hall_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/confectionary_24.svg b/static/icons/confectionary_24.svg
new file mode 100644
index 0000000..5c360c4
--- /dev/null
+++ b/static/icons/confectionary_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/currency_exchange_24.svg b/static/icons/currency_exchange_24.svg
new file mode 100644
index 0000000..b4d2a6e
--- /dev/null
+++ b/static/icons/currency_exchange_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/dental_24.svg b/static/icons/dental_24.svg
new file mode 100644
index 0000000..b7a059a
--- /dev/null
+++ b/static/icons/dental_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/driving_school_24.svg b/static/icons/driving_school_24.svg
new file mode 100644
index 0000000..c22d208
--- /dev/null
+++ b/static/icons/driving_school_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/drugstores_24.svg b/static/icons/drugstores_24.svg
new file mode 100644
index 0000000..359aec6
--- /dev/null
+++ b/static/icons/drugstores_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/dry_cleaning_24.svg b/static/icons/dry_cleaning_24.svg
new file mode 100644
index 0000000..386a004
--- /dev/null
+++ b/static/icons/dry_cleaning_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/equestrian_24.svg b/static/icons/equestrian_24.svg
new file mode 100644
index 0000000..0f6820c
--- /dev/null
+++ b/static/icons/equestrian_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/fallback_24.svg b/static/icons/fallback_24.svg
new file mode 100644
index 0000000..8953d2d
--- /dev/null
+++ b/static/icons/fallback_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/fast_food_24.svg b/static/icons/fast_food_24.svg
new file mode 100644
index 0000000..5904915
--- /dev/null
+++ b/static/icons/fast_food_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/festival_24.svg b/static/icons/festival_24.svg
new file mode 100644
index 0000000..51efc61
--- /dev/null
+++ b/static/icons/festival_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/film_studio_24.svg b/static/icons/film_studio_24.svg
new file mode 100644
index 0000000..e5cd208
--- /dev/null
+++ b/static/icons/film_studio_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/fire_station_24.svg b/static/icons/fire_station_24.svg
new file mode 100644
index 0000000..73765ac
--- /dev/null
+++ b/static/icons/fire_station_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/fitness_24.svg b/static/icons/fitness_24.svg
new file mode 100644
index 0000000..7e9fd41
--- /dev/null
+++ b/static/icons/fitness_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/flower_shop_24.svg b/static/icons/flower_shop_24.svg
new file mode 100644
index 0000000..7e41c29
--- /dev/null
+++ b/static/icons/flower_shop_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/forest_24.svg b/static/icons/forest_24.svg
new file mode 100644
index 0000000..4b0de7d
--- /dev/null
+++ b/static/icons/forest_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/fountain_24.svg b/static/icons/fountain_24.svg
new file mode 100644
index 0000000..ff48095
--- /dev/null
+++ b/static/icons/fountain_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/furniture_store_24.svg b/static/icons/furniture_store_24.svg
new file mode 100644
index 0000000..ed2899d
--- /dev/null
+++ b/static/icons/furniture_store_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/garden_24.svg b/static/icons/garden_24.svg
new file mode 100644
index 0000000..dac7d14
--- /dev/null
+++ b/static/icons/garden_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/gasstation_24.svg b/static/icons/gasstation_24.svg
new file mode 100644
index 0000000..bc7147f
--- /dev/null
+++ b/static/icons/gasstation_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/government_24.svg b/static/icons/government_24.svg
new file mode 100644
index 0000000..1eb5815
--- /dev/null
+++ b/static/icons/government_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/hairdressers_24.svg b/static/icons/hairdressers_24.svg
new file mode 100644
index 0000000..f1f9cff
--- /dev/null
+++ b/static/icons/hairdressers_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/haulier_24.svg b/static/icons/haulier_24.svg
new file mode 100644
index 0000000..5ae0211
--- /dev/null
+++ b/static/icons/haulier_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/helicopter_24.svg b/static/icons/helicopter_24.svg
new file mode 100644
index 0000000..d00d50d
--- /dev/null
+++ b/static/icons/helicopter_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/hospital_24.svg b/static/icons/hospital_24.svg
new file mode 100644
index 0000000..e9bd5cf
--- /dev/null
+++ b/static/icons/hospital_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/hotels_24.svg b/static/icons/hotels_24.svg
new file mode 100644
index 0000000..72a49bb
--- /dev/null
+++ b/static/icons/hotels_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/hypermarket_24.svg b/static/icons/hypermarket_24.svg
new file mode 100644
index 0000000..06d12c8
--- /dev/null
+++ b/static/icons/hypermarket_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/industrial_enterprise_24.svg b/static/icons/industrial_enterprise_24.svg
new file mode 100644
index 0000000..cbdc443
--- /dev/null
+++ b/static/icons/industrial_enterprise_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/information_24.svg b/static/icons/information_24.svg
new file mode 100644
index 0000000..086648e
--- /dev/null
+++ b/static/icons/information_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/kindergarten_24.svg b/static/icons/kindergarten_24.svg
new file mode 100644
index 0000000..9786799
--- /dev/null
+++ b/static/icons/kindergarten_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/landmark_24.svg b/static/icons/landmark_24.svg
new file mode 100644
index 0000000..76104d1
--- /dev/null
+++ b/static/icons/landmark_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/laundry_24.svg b/static/icons/laundry_24.svg
new file mode 100644
index 0000000..de18ee6
--- /dev/null
+++ b/static/icons/laundry_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/library_24.svg b/static/icons/library_24.svg
new file mode 100644
index 0000000..20a8fdb
--- /dev/null
+++ b/static/icons/library_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/malls_24.svg b/static/icons/malls_24.svg
new file mode 100644
index 0000000..6aa6a5f
--- /dev/null
+++ b/static/icons/malls_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/medicine_24.svg b/static/icons/medicine_24.svg
new file mode 100644
index 0000000..e9bd5cf
--- /dev/null
+++ b/static/icons/medicine_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/memorable_event_24.svg b/static/icons/memorable_event_24.svg
new file mode 100644
index 0000000..76104d1
--- /dev/null
+++ b/static/icons/memorable_event_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_24.svg b/static/icons/metro_24.svg
new file mode 100644
index 0000000..2138591
--- /dev/null
+++ b/static/icons/metro_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_bus_24.svg b/static/icons/metro_bus_24.svg
new file mode 100644
index 0000000..7c0d81c
--- /dev/null
+++ b/static/icons/metro_bus_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_cable_24.svg b/static/icons/metro_cable_24.svg
new file mode 100644
index 0000000..e99a406
--- /dev/null
+++ b/static/icons/metro_cable_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_entrance_24.svg b/static/icons/metro_entrance_24.svg
new file mode 100644
index 0000000..4f8746e
--- /dev/null
+++ b/static/icons/metro_entrance_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_funicular_24.svg b/static/icons/metro_funicular_24.svg
new file mode 100644
index 0000000..a276b29
--- /dev/null
+++ b/static/icons/metro_funicular_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_light_24.svg b/static/icons/metro_light_24.svg
new file mode 100644
index 0000000..408f6cd
--- /dev/null
+++ b/static/icons/metro_light_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_monorail_24.svg b/static/icons/metro_monorail_24.svg
new file mode 100644
index 0000000..a8257d0
--- /dev/null
+++ b/static/icons/metro_monorail_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/metro_tram_24.svg b/static/icons/metro_tram_24.svg
new file mode 100644
index 0000000..e15bdaa
--- /dev/null
+++ b/static/icons/metro_tram_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/mobile_phones_24.svg b/static/icons/mobile_phones_24.svg
new file mode 100644
index 0000000..bf50bab
--- /dev/null
+++ b/static/icons/mobile_phones_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/money_coin_24.svg b/static/icons/money_coin_24.svg
new file mode 100644
index 0000000..e49389d
--- /dev/null
+++ b/static/icons/money_coin_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/monument_24.svg b/static/icons/monument_24.svg
new file mode 100644
index 0000000..cae05e6
--- /dev/null
+++ b/static/icons/monument_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/mosque_24.svg b/static/icons/mosque_24.svg
new file mode 100644
index 0000000..3ab8384
--- /dev/null
+++ b/static/icons/mosque_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/mountain_24.svg b/static/icons/mountain_24.svg
new file mode 100644
index 0000000..5db4c06
--- /dev/null
+++ b/static/icons/mountain_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/museum_24.svg b/static/icons/museum_24.svg
new file mode 100644
index 0000000..face4dc
--- /dev/null
+++ b/static/icons/museum_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/nail_studio_24.svg b/static/icons/nail_studio_24.svg
new file mode 100644
index 0000000..33146da
--- /dev/null
+++ b/static/icons/nail_studio_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/office_24.svg b/static/icons/office_24.svg
new file mode 100644
index 0000000..20073f7
--- /dev/null
+++ b/static/icons/office_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/office_service_24.svg b/static/icons/office_service_24.svg
new file mode 100644
index 0000000..20073f7
--- /dev/null
+++ b/static/icons/office_service_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/orthodox_church_24.svg b/static/icons/orthodox_church_24.svg
new file mode 100644
index 0000000..10d8939
--- /dev/null
+++ b/static/icons/orthodox_church_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/park_24.svg b/static/icons/park_24.svg
new file mode 100644
index 0000000..5c6dc3a
--- /dev/null
+++ b/static/icons/park_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/pavilion_24.svg b/static/icons/pavilion_24.svg
new file mode 100644
index 0000000..6691d7e
--- /dev/null
+++ b/static/icons/pavilion_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/pet_playground_24.svg b/static/icons/pet_playground_24.svg
new file mode 100644
index 0000000..7b3511b
--- /dev/null
+++ b/static/icons/pet_playground_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/petshop_24.svg b/static/icons/petshop_24.svg
new file mode 100644
index 0000000..0dc14f3
--- /dev/null
+++ b/static/icons/petshop_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/photo_24.svg b/static/icons/photo_24.svg
new file mode 100644
index 0000000..57bd18c
--- /dev/null
+++ b/static/icons/photo_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/picnic_24.svg b/static/icons/picnic_24.svg
new file mode 100644
index 0000000..4026a1f
--- /dev/null
+++ b/static/icons/picnic_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/pier_24.svg b/static/icons/pier_24.svg
new file mode 100644
index 0000000..12e5a8c
--- /dev/null
+++ b/static/icons/pier_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/playground_24.svg b/static/icons/playground_24.svg
new file mode 100644
index 0000000..184e5f0
--- /dev/null
+++ b/static/icons/playground_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/police_24.svg b/static/icons/police_24.svg
new file mode 100644
index 0000000..310e586
--- /dev/null
+++ b/static/icons/police_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/police_post_24.svg b/static/icons/police_post_24.svg
new file mode 100644
index 0000000..310e586
--- /dev/null
+++ b/static/icons/police_post_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/port_24.svg b/static/icons/port_24.svg
new file mode 100644
index 0000000..31331ca
--- /dev/null
+++ b/static/icons/port_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/post_office_24.svg b/static/icons/post_office_24.svg
new file mode 100644
index 0000000..0edbe03
--- /dev/null
+++ b/static/icons/post_office_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/printing_services_24.svg b/static/icons/printing_services_24.svg
new file mode 100644
index 0000000..dda65e7
--- /dev/null
+++ b/static/icons/printing_services_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/protestant_church_24.svg b/static/icons/protestant_church_24.svg
new file mode 100644
index 0000000..e96115b
--- /dev/null
+++ b/static/icons/protestant_church_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/racing_24.svg b/static/icons/racing_24.svg
new file mode 100644
index 0000000..36e2a17
--- /dev/null
+++ b/static/icons/racing_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/railway_24.svg b/static/icons/railway_24.svg
new file mode 100644
index 0000000..16bbadd
--- /dev/null
+++ b/static/icons/railway_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/railway_station_24.svg b/static/icons/railway_station_24.svg
new file mode 100644
index 0000000..16bbadd
--- /dev/null
+++ b/static/icons/railway_station_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/recycling_24.svg b/static/icons/recycling_24.svg
new file mode 100644
index 0000000..109ab85
--- /dev/null
+++ b/static/icons/recycling_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/restaurants_24.svg b/static/icons/restaurants_24.svg
new file mode 100644
index 0000000..dad9435
--- /dev/null
+++ b/static/icons/restaurants_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/rezervation_24.svg b/static/icons/rezervation_24.svg
new file mode 100644
index 0000000..6b3333b
--- /dev/null
+++ b/static/icons/rezervation_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/sanatorium_24.svg b/static/icons/sanatorium_24.svg
new file mode 100644
index 0000000..60a698b
--- /dev/null
+++ b/static/icons/sanatorium_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/science_24.svg b/static/icons/science_24.svg
new file mode 100644
index 0000000..621d7ce
--- /dev/null
+++ b/static/icons/science_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/skating_rink_24.svg b/static/icons/skating_rink_24.svg
new file mode 100644
index 0000000..ce6782e
--- /dev/null
+++ b/static/icons/skating_rink_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/software_24.svg b/static/icons/software_24.svg
new file mode 100644
index 0000000..1442370
--- /dev/null
+++ b/static/icons/software_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/spa_24.svg b/static/icons/spa_24.svg
new file mode 100644
index 0000000..deeeb29
--- /dev/null
+++ b/static/icons/spa_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/sportcenter_24.svg b/static/icons/sportcenter_24.svg
new file mode 100644
index 0000000..204e87a
--- /dev/null
+++ b/static/icons/sportcenter_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/spring_24.svg b/static/icons/spring_24.svg
new file mode 100644
index 0000000..5aba127
--- /dev/null
+++ b/static/icons/spring_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/stadium_24.svg b/static/icons/stadium_24.svg
new file mode 100644
index 0000000..c1fbe4d
--- /dev/null
+++ b/static/icons/stadium_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/stage_24.svg b/static/icons/stage_24.svg
new file mode 100644
index 0000000..30371fe
--- /dev/null
+++ b/static/icons/stage_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/stenograffia_24.svg b/static/icons/stenograffia_24.svg
new file mode 100644
index 0000000..4fe7388
--- /dev/null
+++ b/static/icons/stenograffia_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/supermarket_24.svg b/static/icons/supermarket_24.svg
new file mode 100644
index 0000000..acc4fb7
--- /dev/null
+++ b/static/icons/supermarket_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/sushi_24.svg b/static/icons/sushi_24.svg
new file mode 100644
index 0000000..8fb2ca6
--- /dev/null
+++ b/static/icons/sushi_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/swimming_pool_24.svg b/static/icons/swimming_pool_24.svg
new file mode 100644
index 0000000..18bef0d
--- /dev/null
+++ b/static/icons/swimming_pool_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/synagogue_24.svg b/static/icons/synagogue_24.svg
new file mode 100644
index 0000000..4a23c7c
--- /dev/null
+++ b/static/icons/synagogue_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/tailor_24.svg b/static/icons/tailor_24.svg
new file mode 100644
index 0000000..40fb928
--- /dev/null
+++ b/static/icons/tailor_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/taxi_24.svg b/static/icons/taxi_24.svg
new file mode 100644
index 0000000..b762696
--- /dev/null
+++ b/static/icons/taxi_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/theatre_24.svg b/static/icons/theatre_24.svg
new file mode 100644
index 0000000..45ed609
--- /dev/null
+++ b/static/icons/theatre_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/ticket_office_24.svg b/static/icons/ticket_office_24.svg
new file mode 100644
index 0000000..91e4532
--- /dev/null
+++ b/static/icons/ticket_office_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/tire_fitting_24.svg b/static/icons/tire_fitting_24.svg
new file mode 100644
index 0000000..b1f6f5d
--- /dev/null
+++ b/static/icons/tire_fitting_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/tram_24.svg b/static/icons/tram_24.svg
new file mode 100644
index 0000000..e15bdaa
--- /dev/null
+++ b/static/icons/tram_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/trash_24.svg b/static/icons/trash_24.svg
new file mode 100644
index 0000000..3352e86
--- /dev/null
+++ b/static/icons/trash_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/travel_agency_24.svg b/static/icons/travel_agency_24.svg
new file mode 100644
index 0000000..903d56d
--- /dev/null
+++ b/static/icons/travel_agency_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/viewpoint_24.svg b/static/icons/viewpoint_24.svg
new file mode 100644
index 0000000..6e4d088
--- /dev/null
+++ b/static/icons/viewpoint_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/waterfall_24.svg b/static/icons/waterfall_24.svg
new file mode 100644
index 0000000..3fb0acc
--- /dev/null
+++ b/static/icons/waterfall_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/waterpark_24.svg b/static/icons/waterpark_24.svg
new file mode 100644
index 0000000..a2230bb
--- /dev/null
+++ b/static/icons/waterpark_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/wc_24.svg b/static/icons/wc_24.svg
new file mode 100644
index 0000000..7c5922f
--- /dev/null
+++ b/static/icons/wc_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/icons/zoo_24.svg b/static/icons/zoo_24.svg
new file mode 100644
index 0000000..4914b81
--- /dev/null
+++ b/static/icons/zoo_24.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tools/icons/fetch-colors.ts b/tools/icons/fetch-colors.ts
new file mode 100644
index 0000000..75c1b5b
--- /dev/null
+++ b/tools/icons/fetch-colors.ts
@@ -0,0 +1,76 @@
+import {Color, Api as FigmaApi, Node} from 'figma-api';
+
+/** The name of the canvas in the file from which the colors will be loaded */
+const CANVAS_NAME = 'colors';
+const PALETTE_NAME = 'rubrics';
+
+const PRIMARY_DAY = 'maps_pin_primary_day';
+const PRIMARY_NIGHT = 'maps_pin_primary_night';
+
+type RubricColors = {
+ rubricName: string;
+ primaryDay: string;
+ primaryNight: string;
+};
+
+export type MarkerColors = {
+ day: string;
+ night: string;
+};
+
+export type FetchedColors = {
+ colors: MarkerColors[];
+};
+
+export const fetchFigmaColors = async (): Promise => {
+ const personalAccessToken: string | undefined = process.env.FIGMA_API_TOKEN;
+ const fileId: string | undefined = process.env.FIGMA_FILE_ID;
+
+ if (!personalAccessToken) {
+ throw new Error('No Figma access token found in environment variable FIGMA_API_TOKEN');
+ }
+ if (!fileId) {
+ throw new Error('No Figma file id found in environment variable FIGMA_FILE_ID');
+ }
+
+ const api = new FigmaApi({personalAccessToken});
+ const file = await api.getFile(fileId);
+ const canvas = file.document.children.find((child) => child.name === CANVAS_NAME) as Node<'CANVAS'>;
+ const rubricsPalette = canvas.children.find((child) => child.name === PALETTE_NAME) as Node<'GROUP'>;
+ const rubrics = rubricsPalette.children.filter(({name}) => !name.includes('fallback')) as Node<'GROUP'>[];
+
+ const rubricColors = rubrics.reduce((rubricColors, {name, children}) => {
+ const colors = children as Node<'RECTANGLE'>[];
+
+ const primaryDay = colors.find((color) => color.name === PRIMARY_DAY)?.fills[0].color;
+ const primaryNight = colors.find((color) => color.name === PRIMARY_NIGHT)?.fills[0].color;
+
+ if (primaryDay === undefined || primaryNight === undefined) {
+ return rubricColors;
+ }
+
+ return rubricColors.concat({
+ rubricName: name,
+ primaryDay: rgbaToHex(primaryDay),
+ primaryNight: rgbaToHex(primaryNight)
+ });
+ }, [] as RubricColors[]);
+
+ const dayNightColorsMap = rubricColors.reduce((colorsMap, {primaryDay, primaryNight}) => {
+ colorsMap.set(primaryDay, primaryNight);
+ return colorsMap;
+ }, new Map());
+
+ const colors = Array.from(dayNightColorsMap.entries()).map(([day, night]) => ({day, night}));
+ return {colors};
+};
+
+const rgbaToHex = (rgba: Color): string => {
+ const r255 = Math.floor(rgba.r * 255);
+ const g255 = Math.floor(rgba.g * 255);
+ const b255 = Math.floor(rgba.b * 255);
+ const a255 = Math.floor(rgba.a * 255);
+ return '#' + componentToHex(r255) + componentToHex(g255) + componentToHex(b255) + componentToHex(a255);
+};
+
+const componentToHex = (c: number): string => c.toString(16).padStart(2, '0');
diff --git a/tools/icons/fetch-icons.ts b/tools/icons/fetch-icons.ts
new file mode 100644
index 0000000..3ab79e4
--- /dev/null
+++ b/tools/icons/fetch-icons.ts
@@ -0,0 +1,183 @@
+import {Api as FigmaApi, isNodeType, Node} from 'figma-api';
+import {GetImageResult} from 'figma-api/lib/api-types';
+import lodashChunk from 'lodash/chunk';
+
+export type IconDescription = {
+ componentId: string;
+ name: string;
+};
+
+export type IconDescriptionWithLink = IconDescription & {
+ link: string;
+};
+
+/** The name of the canvas in the file from which the icons will be loaded */
+const CANVAS_NAME = 'glyphs';
+/** Available icon sizes specified in Figma */
+const AVAILABLE_SIZES = [24];
+/** RegExp for getting the region code from the component name */
+const REGION_CODE_REGEXP = /_([a-z]{2})_/;
+/** RegExp for getting the size from the component name*/
+export const SIZE_REGEXP = /_([0-9]{2})/;
+/** RegExp to discard rubrics fallbacks */
+const RUBRIC_FALLBACK_REGEXP = /fallback_.+\d{2}$/;
+const INTL_REGION_CODES = new Intl.DisplayNames(['en'], {type: 'region'});
+/** A number between 0.01 and 4, the image scaling factor */
+const IMAGE_SCALE = 1;
+const ICONS_PER_CHUNK = 100;
+
+/**
+ * Gets a description and links to download icons from Figma
+ * @returns Description of the icons and links to download them, which are located in Figma.
+ */
+export async function fetchFigmaIcons(): Promise {
+ const personalAccessToken: string | undefined = process.env.FIGMA_API_TOKEN;
+ const fileId: string | undefined = process.env.FIGMA_FILE_ID;
+
+ if (!personalAccessToken) {
+ throw new Error('No Figma access token found in environment variable FIGMA_API_TOKEN');
+ }
+ if (!fileId) {
+ throw new Error('No Figma file id found in environment variable FIGMA_FILE_ID');
+ }
+
+ const api = new FigmaApi({personalAccessToken});
+ const components = await getComponents(fileId, CANVAS_NAME, api);
+ const iconDescriptions = getIconDescriptions(components, AVAILABLE_SIZES);
+ const imageLinks = await getImageLinks(iconDescriptions, fileId, api);
+ return imageLinks;
+}
+
+/**
+ * Get components that are included in the canvas from Figma
+ * @param fileId - ID of the document where the canvas is located
+ * @param canvasName - The name of the canvas from which the components come
+ * @param api - Object for accessing the Figma API
+ * @returns Array of component nodes
+ */
+const getComponents = async (fileId: string, canvasName: string, api: FigmaApi): Promise[]> => {
+ const file = await api.getFile(fileId);
+
+ const canvas = file.document.children.find((child) => child.name === canvasName) as Node<'CANVAS'>;
+ if (!canvas) {
+ throw new Error(`Canvas "${canvasName}" not found!`);
+ }
+
+ return canvas.children.reduce((components, child) => {
+ if (!isNodeType(child, 'GROUP')) {
+ return components;
+ }
+ const newComponents = child.children.filter((child) => isNodeType(child, 'INSTANCE')) as Node<'COMPONENT'>[];
+ return components.concat(newComponents);
+ }, [] as Node<'COMPONENT'>[]);
+};
+
+/**
+ * Gets a description of icons from the component nodes
+ * @param components - Array of component nodes
+ * @param availableSizes - Acceptable icon sizes
+ * @returns Array of objects with icon descriptions
+ */
+const getIconDescriptions = (components: Node<'COMPONENT'>[], availableSizes: number[]): IconDescription[] => {
+ return components
+ .filter((component) => {
+ // the component must have export settings
+ if (component.exportSettings === undefined || component.exportSettings.length === 0) {
+ return false;
+ }
+ // the component should not have a regional code
+ if (componentNameHasRegionCode(component.name)) {
+ return false;
+ }
+ // the component must be of allowed size and square
+ if (!componentAvailableSize(component.name, availableSizes)) {
+ return false;
+ }
+ // without fallback icons
+ if (RUBRIC_FALLBACK_REGEXP.test(component.name)) {
+ return false;
+ }
+ const {height, width} = component.absoluteBoundingBox;
+ return height === width;
+ })
+ .map((component) => ({componentId: component.id, name: component.name}));
+};
+
+/**
+ * Adds download links to the icon descriptions
+ * @param descriptions - Array of objects with icon descriptions
+ * @param fileId - ID of the document where the icons are located
+ * @param api - Object for accessing the Figma API
+ * @returns Array of objects with descriptions and download links for icons
+ */
+const getImageLinks = async (
+ descriptions: IconDescription[],
+ fileId: string,
+ api: FigmaApi
+): Promise => {
+ const chunks = lodashChunk(descriptions, ICONS_PER_CHUNK);
+ const linkChunks = await Promise.all(
+ chunks.map((chunk) =>
+ api.getImage(fileId, {
+ ids: chunk.map((icon) => icon.componentId).join(','),
+ scale: IMAGE_SCALE,
+ format: 'svg'
+ })
+ )
+ );
+ const links = linkChunks.reduce(
+ (memo, chunk) => {
+ if (chunk.err) {
+ memo.err = chunk.err;
+ }
+ if (chunk.images) {
+ memo.images = {...memo.images, ...chunk.images};
+ }
+ return memo;
+ },
+ {images: {}}
+ );
+
+ if (links.err) {
+ throw new Error(`Error while loading links: ${links.err}`);
+ }
+
+ return descriptions.reduce((descriptionsWithLink, description) => {
+ const link = links.images[description.componentId];
+ if (link) {
+ return descriptionsWithLink.concat({...description, link});
+ }
+ return descriptionsWithLink;
+ }, []);
+};
+
+/**
+ * Checks that the component name has a region code
+ * @param componentName - Component name
+ * @returns `true` if the component name contains the region code
+ */
+const componentNameHasRegionCode = (componentName: string): boolean => {
+ const regionMatch = REGION_CODE_REGEXP.exec(componentName);
+ if (regionMatch === null) {
+ return false;
+ }
+ const [, regionCode] = regionMatch;
+ const uppercaseCode = regionCode.toUpperCase();
+ return INTL_REGION_CODES.of(uppercaseCode) !== uppercaseCode;
+};
+
+/**
+ * Checks that the allowed size is specified in the component name
+ * @param componentName - Component name
+ * @param availableSizes - Array with acceptable icon sizes
+ * @returns `true` if the component name contains a valid size
+ */
+const componentAvailableSize = (componentName: string, availableSizes: number[]): boolean => {
+ const sizeMatch = SIZE_REGEXP.exec(componentName);
+ if (sizeMatch === null) {
+ return false;
+ }
+ const [, rawSize] = sizeMatch;
+ const size = rawSize ? Number(rawSize) : undefined;
+ return availableSizes.includes(size as number);
+};
diff --git a/tools/icons/generate-colors.ts b/tools/icons/generate-colors.ts
new file mode 100644
index 0000000..4f263aa
--- /dev/null
+++ b/tools/icons/generate-colors.ts
@@ -0,0 +1,23 @@
+import fs from 'fs/promises';
+import path from 'path';
+import {prettierFormat} from '../utils/prettier-format';
+import {FetchedColors} from './fetch-colors';
+import {SRC_ICONS_PATH} from './paths';
+
+/** Human-readable names for colors. They are selected manually */
+const colorNames = ['darkgray', 'pink', 'seawave', 'orchid', 'steelblue', 'bluebell', 'ceil', 'green', 'darksalmon'];
+
+export const generateColorsFile = async (fetchedColors: FetchedColors) => {
+ const colorsObjectValues = fetchedColors.colors.map(({day, night}, i) => {
+ return `${colorNames[i]}:{day:'${day}',night:'${night}'},`;
+ });
+ const content = `
+ /** Don't edit manually only color names. Generated by script: ./tools/icons/generate-colors.ts */
+ export const iconColors = {
+ ${colorsObjectValues.join('\n')}
+ } as const;
+ export type IconColor = keyof typeof iconColors`;
+
+ const formattedContent = await prettierFormat(content, 'typescript');
+ await fs.writeFile(path.join(SRC_ICONS_PATH, 'icon-colors.generated.ts'), formattedContent);
+};
diff --git a/tools/icons/generate-docs.ts b/tools/icons/generate-docs.ts
new file mode 100644
index 0000000..b7753c6
--- /dev/null
+++ b/tools/icons/generate-docs.ts
@@ -0,0 +1,31 @@
+import {existsSync} from 'fs';
+import fs from 'fs/promises';
+import path from 'path';
+import {prettierFormat} from '../utils/prettier-format';
+import {DOCS_FILE_PATH, STATIC_ICONS_PATH} from './paths';
+
+const WARNING = ``;
+const TITLE = '# List of supported icons';
+const TABLE_HEADER = `
+| Name | Normal Size |
+| --- | --- |
+`;
+
+export const generateIconsDocsList = async (iconNames: string[]) => {
+ let content = `${WARNING}\n\n${TITLE}\n\n${TABLE_HEADER}`;
+ content += iconNames
+ .map((name) => {
+ const normalFileName = `${name}_24.svg`;
+
+ const normalAbsolutePath = path.join(STATIC_ICONS_PATH, normalFileName);
+
+ const normalRelativePath = `../static/icons/${normalFileName}`;
+
+ const normalIcon = existsSync(normalAbsolutePath) ? `![${name}](${normalRelativePath})` : `none`;
+
+ return `| ${name} | ${normalIcon} |`;
+ })
+ .join('\n');
+ const formattedContent = await prettierFormat(content, 'markdown');
+ await fs.writeFile(path.join(DOCS_FILE_PATH, 'icons.generated.md'), formattedContent);
+};
diff --git a/tools/icons/generate-imports.ts b/tools/icons/generate-imports.ts
new file mode 100644
index 0000000..8cca0ad
--- /dev/null
+++ b/tools/icons/generate-imports.ts
@@ -0,0 +1,31 @@
+import fs from 'fs/promises';
+import path from 'path';
+import {prettierFormat} from '../utils/prettier-format';
+import {IconDescription} from './fetch-icons';
+import {SRC_ICONS_PATH} from './paths';
+
+const WARNING = `/** Don't edit manually. Generated by script: ./tools/icons/generate-imports.ts */`;
+
+export const generateImports = async (iconsDescription: IconDescription[], iconNames: string[]) => {
+ const importList = iconsDescription
+ .map((description) => `import ${description.name} from '../../static/icons/${description.name}.svg'`)
+ .join('\n');
+
+ const iconNamesObject = iconNames
+ .map((iconName) => {
+ const normalIcon = iconsDescription.find((description) => description.name === `${iconName}_24`);
+ return `${iconName}:${normalIcon?.name ?? 'null'},`;
+ })
+ .join('\n');
+
+ const fileContent = `
+ ${WARNING}
+ ${importList}
+
+ import type {Icons} from './types';
+ export const icons: Icons = {
+ ${iconNamesObject}
+ }`;
+ const formattedContent = await prettierFormat(fileContent, 'typescript');
+ await fs.writeFile(path.join(SRC_ICONS_PATH, 'icons.generated.ts'), formattedContent);
+};
diff --git a/tools/icons/generate-types.ts b/tools/icons/generate-types.ts
new file mode 100644
index 0000000..b5cf9c9
--- /dev/null
+++ b/tools/icons/generate-types.ts
@@ -0,0 +1,14 @@
+import fs from 'fs/promises';
+import path from 'path';
+import {prettierFormat} from '../utils/prettier-format';
+import {SRC_ICONS_PATH} from './paths';
+
+export const generateIconsTypes = async (iconNames: string[]) => {
+ const type = 'IconName';
+ const content = `
+/** Don't edit manually. Generated by script: ./tools/icons/generate-types.ts */
+export type ${type} =${iconNames.map((name) => `| '${name}'`).join('\n')};
+`;
+ const formattedContent = await prettierFormat(content, 'typescript');
+ await fs.writeFile(path.join(SRC_ICONS_PATH, 'icon-name.generated.ts'), formattedContent);
+};
diff --git a/tools/icons/get-image-files.ts b/tools/icons/get-image-files.ts
new file mode 100644
index 0000000..54955a0
--- /dev/null
+++ b/tools/icons/get-image-files.ts
@@ -0,0 +1,66 @@
+import got from 'got';
+import {optimize} from 'svgo';
+import {IconDescription, IconDescriptionWithLink} from './fetch-icons';
+
+/** Maximum number of retries when loading an icon */
+const MAX_RETRIES = 20;
+/** Our designer marks these icons with this color that do not need to be worked on yet */
+const ERROR_COLOR_REGEXP = /fill="#C90D0D"/;
+/** Our designer marks icons with `fill-opacity="0.1"` that don't need to be worked on yet */
+const FILL_OPACITY_REGEXP = /fill-opacity="0.1"/;
+/** Default icon color from Figma */
+const FILL_COLOR_REGEXP = /fill="black"/g;
+
+export type IconDescriptionWithData = IconDescription & {
+ data: Buffer;
+};
+
+/**
+ * Downloads icons from Figma using the link from the description and transforms them
+ * @param icons - Array of objects with icon descriptions
+ * @returns Array of objects with icon descriptions and transformed downloaded data
+ */
+export const downloadAndTransform = async (icons: IconDescriptionWithLink[]): Promise => {
+ const iconsWithData = await getImageFiles(icons);
+ return iconsWithData.reduce((icons, currentIcon) => {
+ const iconDataString = currentIcon.data.toString();
+ if (iconDataString.match(ERROR_COLOR_REGEXP) || iconDataString.match(FILL_OPACITY_REGEXP)) {
+ return icons;
+ }
+ const replacedFillColorIconData = iconDataString.replace(FILL_COLOR_REGEXP, 'fill="currentColor"');
+ const optimizedIcon = optimize(replacedFillColorIconData);
+ return icons.concat({...currentIcon, data: Buffer.from(optimizedIcon.data)});
+ }, [] as IconDescriptionWithData[]);
+};
+
+/**
+ * Downloads icons from Figma using the link from the description
+ * @param icons - Array of objects with icon descriptions
+ * @returns Array of objects with icon descriptions and downloaded data
+ */
+const getImageFiles = async (icons: IconDescriptionWithLink[]): Promise => {
+ return Promise.all(
+ icons.map(async (icon) => {
+ try {
+ const file = await fetchFile(icon.link);
+ return {...file, name: icon.name, componentId: icon.componentId};
+ } catch (e) {
+ e.message = `${icon.name}: ${e.message}`;
+ throw e;
+ }
+ })
+ );
+};
+
+/**
+ * Download the file from the specified URL
+ * @param url - URL where the file is located
+ * @returns Downloaded data as a buffer
+ */
+const fetchFile = async (url: string) => {
+ const response = await got(url, {timeout: 60 * 1000, retry: MAX_RETRIES});
+ if (!response.body) {
+ throw new Error('No response body.');
+ }
+ return {data: response.body};
+};
diff --git a/tools/icons/get-uniq-names.ts b/tools/icons/get-uniq-names.ts
new file mode 100644
index 0000000..6f0adf4
--- /dev/null
+++ b/tools/icons/get-uniq-names.ts
@@ -0,0 +1,6 @@
+import {uniq} from 'lodash';
+import {IconDescription, SIZE_REGEXP} from './fetch-icons';
+
+export const getUniqNames = (icons: IconDescription[]) => {
+ return uniq(icons.map(({name}) => name.replace(SIZE_REGEXP, ''))).sort();
+};
diff --git a/tools/icons/local.ts b/tools/icons/local.ts
new file mode 100644
index 0000000..09e3481
--- /dev/null
+++ b/tools/icons/local.ts
@@ -0,0 +1,43 @@
+import fs from 'fs/promises';
+import path from 'path';
+import {IconDescriptionWithData} from './get-image-files';
+import {STATIC_ICONS_PATH} from './paths';
+
+export type LocalIconDescription = {
+ name: string;
+};
+
+export const getLocalIcons = async (): Promise => {
+ const currentFilenames = await fs.readdir(STATIC_ICONS_PATH);
+ const descriptions: LocalIconDescription[] = await Promise.all(
+ currentFilenames.map(async (filename) => {
+ const fileExtension = path.parse(filename).ext.slice(1);
+ if (fileExtension !== 'svg' && fileExtension !== 'png') {
+ throw new Error('Unknown file extension.');
+ }
+ const cleanFilename = path.parse(filename).name;
+ return {
+ name: cleanFilename
+ };
+ })
+ );
+ return descriptions;
+};
+
+export const updateLocalFiles = async (icons: IconDescriptionWithData[]) => {
+ await Promise.all(
+ icons.map((icon) => {
+ const filePath = path.join(STATIC_ICONS_PATH, `${icon.name}.svg`);
+ return fs.writeFile(filePath, icon.data, 'utf-8');
+ })
+ );
+};
+
+export const deleteLocalFiles = async (iconsToDelete: LocalIconDescription[]) => {
+ await Promise.all(
+ iconsToDelete.map((icon) => {
+ const filePath = path.join(STATIC_ICONS_PATH, `${icon.name}.svg`);
+ return fs.rm(filePath);
+ })
+ );
+};
diff --git a/tools/icons/paths.ts b/tools/icons/paths.ts
new file mode 100644
index 0000000..8a7d4b6
--- /dev/null
+++ b/tools/icons/paths.ts
@@ -0,0 +1,6 @@
+import path from 'path';
+
+export const BASE_DIR = path.join(__dirname, '../../');
+export const STATIC_ICONS_PATH = path.join(BASE_DIR, 'static/icons');
+export const SRC_ICONS_PATH = path.join(BASE_DIR, 'src/icons');
+export const DOCS_FILE_PATH = path.join(BASE_DIR, 'docs');
diff --git a/tools/icons/update-icons.ts b/tools/icons/update-icons.ts
new file mode 100644
index 0000000..4ab6b2b
--- /dev/null
+++ b/tools/icons/update-icons.ts
@@ -0,0 +1,29 @@
+import {differenceBy, intersectionBy} from 'lodash';
+import {IconDescription, fetchFigmaIcons} from './fetch-icons';
+import {deleteLocalFiles, getLocalIcons, updateLocalFiles} from './local';
+import {downloadAndTransform} from './get-image-files';
+import {Spinner} from 'nanospinner';
+
+export const updateIcons = async (spinner: Spinner): Promise => {
+ spinner.update({text: 'Getting information about icons from Figma'});
+ const figmaIcons = await fetchFigmaIcons();
+
+ spinner.update({text: 'Getting information about current local icons'});
+ const localIcons = await getLocalIcons();
+
+ spinner.update({text: 'Downloading and transforming icons from Figma'});
+ const iconsWithData = await downloadAndTransform(figmaIcons);
+
+ spinner.update({text: 'Updating local icons'});
+ await updateLocalFiles(iconsWithData);
+
+ const existingLocalIcons = intersectionBy(localIcons, iconsWithData, (d) => d.name);
+ const iconsToDelete = differenceBy(localIcons, existingLocalIcons, (d) => d.name);
+
+ spinner.update({text: 'Removing unnecessary old local icons'});
+ await deleteLocalFiles(iconsToDelete);
+
+ return iconsWithData
+ .map(({componentId, name}) => ({componentId, name}))
+ .sort((a, b) => a.name.localeCompare(b.name));
+};
diff --git a/tools/scripts/sync-colors.ts b/tools/scripts/sync-colors.ts
new file mode 100644
index 0000000..63b8530
--- /dev/null
+++ b/tools/scripts/sync-colors.ts
@@ -0,0 +1,24 @@
+import {createSpinner} from 'nanospinner';
+import {fetchFigmaColors} from '../icons/fetch-colors';
+import {generateColorsFile} from '../icons/generate-colors';
+
+async function main() {
+ const spinner = createSpinner();
+ try {
+ spinner.start({text: 'Start sync colors'});
+
+ spinner.update({text: 'Getting information about colors from Figma'});
+ const fetchedColors = await fetchFigmaColors();
+
+ spinner.update({text: 'Updating the file with colors'});
+ await generateColorsFile(fetchedColors);
+
+ spinner.success({text: 'Colors are successfully synchronized'});
+ } catch (error) {
+ spinner.error({text: error.message || error.toString()});
+ }
+}
+
+main().catch(() => {
+ process.exit(1);
+});
diff --git a/tools/scripts/sync-icons.ts b/tools/scripts/sync-icons.ts
new file mode 100644
index 0000000..def309d
--- /dev/null
+++ b/tools/scripts/sync-icons.ts
@@ -0,0 +1,33 @@
+import {createSpinner} from 'nanospinner';
+import {generateIconsDocsList} from '../icons/generate-docs';
+import {generateImports} from '../icons/generate-imports';
+import {generateIconsTypes} from '../icons/generate-types';
+import {getUniqNames} from '../icons/get-uniq-names';
+import {updateIcons} from '../icons/update-icons';
+
+async function main() {
+ const spinner = createSpinner();
+ try {
+ spinner.start({text: 'Start sync icons'});
+
+ const iconsDescription = await updateIcons(spinner);
+ const iconNames = getUniqNames(iconsDescription);
+
+ spinner.update({text: 'Generating a file with typescript icon types'});
+ await generateIconsTypes(iconNames);
+
+ spinner.update({text: 'Generating a file with import icons svg'});
+ await generateImports(iconsDescription, iconNames);
+
+ spinner.update({text: 'Generating a markdown file with a list of available icons'});
+ await generateIconsDocsList(iconNames);
+
+ spinner.success({text: 'Icons are successfully synchronized'});
+ } catch (error) {
+ spinner.error({text: error.message || error.toString()});
+ }
+}
+
+main().catch(() => {
+ process.exit(1);
+});
diff --git a/tools/utils/prettier-format.ts b/tools/utils/prettier-format.ts
new file mode 100644
index 0000000..8afc85a
--- /dev/null
+++ b/tools/utils/prettier-format.ts
@@ -0,0 +1,6 @@
+import prettier from 'prettier';
+
+export const prettierFormat = async (rawContent: string, parser: prettier.Options['parser']): Promise => {
+ const prettierConfig = await prettier.resolveConfig(process.cwd());
+ return prettier.format(rawContent, {...prettierConfig, parser});
+};
diff --git a/tsconfig.json b/tsconfig.json
index c9fd3e0..93b76eb 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "@mappable-world/mappable-cli",
"compilerOptions": {
+ "moduleResolution": "Node16",
"lib": ["dom", "dom.iterable", "esnext"],
"moduleResolution": "Node16",
"typeRoots": ["./node_modules/@types", "./node_modules/@mappable-world", "./types"]