diff --git a/package-lock.json b/package-lock.json index d4eb7f9..4c7fce0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,12 @@ "": { "name": "map-journal", "version": "0.0.0", + "dependencies": { + "d3": "^7.9.0", + "flag-icons": "^7.5.0", + "topojson-client": "^3.1.0", + "world-atlas": "^2.0.2" + }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.55.5", @@ -488,6 +494,416 @@ "node": ">=6" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -498,6 +914,15 @@ "node": ">=0.10.0" } }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -558,6 +983,12 @@ } } }, + "node_modules/flag-icons": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-7.5.0.tgz", + "integrity": "sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg==", + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -573,6 +1004,27 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -940,6 +1392,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -974,6 +1432,18 @@ "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1029,6 +1499,26 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "license": "ISC", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/topojson-client/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1135,6 +1625,12 @@ } } }, + "node_modules/world-atlas": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/world-atlas/-/world-atlas-2.0.2.tgz", + "integrity": "sha512-IXfV0qwlKXpckz1FhwXVwKRjiIhOnWttOskm5CtxMsjgE/MXAYRHWJqgXOpM8IkcPBoXnyTU5lFHcYa5ChG0LQ==", + "license": "ISC" + }, "node_modules/zimmerframe": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", diff --git a/package.json b/package.json index 0d60aba..c363719 100644 --- a/package.json +++ b/package.json @@ -12,5 +12,11 @@ "@sveltejs/vite-plugin-svelte": "^7.1.2", "svelte": "^5.55.5", "vite": "^8.0.12" + }, + "dependencies": { + "d3": "^7.9.0", + "flag-icons": "^7.5.0", + "topojson-client": "^3.1.0", + "world-atlas": "^2.0.2" } } diff --git a/src/App.svelte b/src/App.svelte index d6a918d..35ecae6 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,14 +1,36 @@ -
- -
+ (screen = s)}> + {#if screen === 'worldmap'} +
+
+ +
+ +
+ {:else} + + {/if} +
diff --git a/src/app.css b/src/app.css index 527d4fb..26d4db9 100644 --- a/src/app.css +++ b/src/app.css @@ -1,296 +1,128 @@ +@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,200;12..96,300;12..96,400&display=swap'); + +/* ── Color tokens ─────────────────────────────────────────── */ :root { - --text: #6b6375; - --text-h: #08060d; - --bg: #fff; - --border: #e5e4e7; - --code-bg: #f4f3ec; - --accent: #aa3bff; - --accent-bg: rgba(170, 59, 255, 0.1); - --accent-border: rgba(170, 59, 255, 0.5); - --social-bg: rgba(244, 243, 236, 0.5); - --shadow: - rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; + /* Indigo & Lavender palette */ + --accent: #6366f1; /* indigo-500 */ + --accent-dark: #4f46e5; /* indigo-600 */ + --accent-light: #818cf8; /* indigo-400 */ + --accent-bg: rgba(99, 102, 241, 0.08); + --accent-border: rgba(99, 102, 241, 0.35); - --sans: system-ui, 'Segoe UI', Roboto, sans-serif; - --heading: system-ui, 'Segoe UI', Roboto, sans-serif; - --mono: ui-monospace, Consolas, monospace; + --lavender: #c4b5fd; /* violet-300 — lavender highlight */ + --lavender-bg: rgba(196, 181, 253, 0.15); - font: 18px/145% var(--sans); - letter-spacing: 0.18px; - color-scheme: light dark; + /* Neutrals */ + --text: #6b7280; /* body copy */ + --text-h: #1e1b4b; /* headings — deep indigo-950 */ + --text-sub: #9ca3af; /* captions / secondary */ + --bg: #fafafe; /* faint indigo tint on white */ + --bg-raised: #ffffff; + --border: #e0e7ff; /* indigo-100 */ + --shadow: rgba(99, 102, 241, 0.12) 0 4px 24px -4px; + + /* Typography */ + --sans: 'Bricolage Grotesque', system-ui, sans-serif; + --heading: 'Bricolage Grotesque', system-ui, sans-serif; + --mono: ui-monospace, Consolas, monospace; + + /* Type scale */ + --text-xs: 11px; + --text-sm: 13px; + --text-base: 14px; + --text-md: 16px; + --text-lg: 20px; + --text-xl: 26px; + --text-2xl: 32px; + + font-family: var(--sans); + font-size: var(--text-base); + line-height: 1.6; + font-weight: 400; + letter-spacing: 0.01em; color: var(--text); background: var(--bg); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - - @media (max-width: 1024px) { - font-size: 16px; - } } +/* ── Dark mode ────────────────────────────────────────────── */ @media (prefers-color-scheme: dark) { :root { - --text: #9ca3af; - --text-h: #f3f4f6; - --bg: #16171d; - --border: #2e303a; - --code-bg: #1f2028; - --accent: #c084fc; - --accent-bg: rgba(192, 132, 252, 0.15); - --accent-border: rgba(192, 132, 252, 0.5); - --social-bg: rgba(47, 48, 58, 0.5); - --shadow: - rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; - } + --accent: #818cf8; + --accent-dark: #6366f1; + --accent-light: #a5b4fc; + --accent-bg: rgba(129, 140, 248, 0.12); + --accent-border: rgba(129, 140, 248, 0.35); - #social .button-icon { - filter: invert(1) brightness(2); + --lavender: #a78bfa; + --lavender-bg: rgba(167, 139, 250, 0.12); + + --text: #9ca3af; + --text-h: #e0e7ff; + --text-sub: #6b7280; + --bg: #0f0e1a; + --bg-raised: #16152a; + --border: #2e2a5e; + --shadow: rgba(0, 0, 0, 0.5) 0 4px 24px -4px; } } -body { +/* ── Reset ────────────────────────────────────────────────── */ +*, *::before, *::after { + box-sizing: border-box; margin: 0; + padding: 0; } -h1, -h2 { - font-family: var(--heading); - font-weight: 500; +html, body, #app { + width: 100%; + height: 100%; + overflow: hidden; +} + +/* ── Text hierarchy ───────────────────────────────────────── */ +h1 { + font-size: var(--text-2xl); + font-weight: 400; + line-height: 1.15; + letter-spacing: -0.6px; color: var(--text-h); } -h1 { - font-size: 56px; - letter-spacing: -1.68px; - margin: 32px 0; - @media (max-width: 1024px) { - font-size: 36px; - margin: 20px 0; - } -} h2 { - font-size: 24px; - line-height: 118%; - letter-spacing: -0.24px; - margin: 0 0 8px; - @media (max-width: 1024px) { - font-size: 20px; - } + font-size: var(--text-xl); + font-weight: 400; + line-height: 1.2; + letter-spacing: -0.4px; + color: var(--text-h); } + +h3 { + font-size: var(--text-lg); + font-weight: 300; + line-height: 1.3; + color: var(--text-h); +} + +h4, h5, h6 { + font-size: var(--text-md); + font-weight: 300; + color: var(--text-h); +} + p { margin: 0; + color: var(--text); } -code, -.counter { - font-family: var(--mono); - display: inline-flex; - border-radius: 4px; - color: var(--text-h); -} - -code { - font-size: 15px; - line-height: 135%; - padding: 4px 8px; - background: var(--code-bg); -} - -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; +/* Eyebrow / label style */ +.label-xs { + font-size: var(--text-xs); + font-weight: 600; + letter-spacing: 0.1em; + text-transform: uppercase; color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; - - &:hover { - border-color: var(--accent-border); - } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - } -} - -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); - } -} - -#app { - width: 1126px; - max-width: 100%; - margin: 0 auto; - text-align: center; - border-inline: 1px solid var(--border); - min-height: 100svh; - display: flex; - flex-direction: column; - box-sizing: border-box; -} - -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } -} - -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { - position: relative; - width: 100%; - - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; - } - - &::before { - left: 0; - border-left-color: var(--border); - } - &::after { - right: 0; - border-right-color: var(--border); - } } diff --git a/src/lib/layout/Footer.svelte b/src/lib/layout/Footer.svelte new file mode 100644 index 0000000..c0a1d01 --- /dev/null +++ b/src/lib/layout/Footer.svelte @@ -0,0 +1,24 @@ + + + + + diff --git a/src/lib/layout/Layout.svelte b/src/lib/layout/Layout.svelte new file mode 100644 index 0000000..ecff737 --- /dev/null +++ b/src/lib/layout/Layout.svelte @@ -0,0 +1,33 @@ + + +
+ +
+ {@render children()} +
+
+ + diff --git a/src/lib/layout/TopBar.svelte b/src/lib/layout/TopBar.svelte new file mode 100644 index 0000000..3149de7 --- /dev/null +++ b/src/lib/layout/TopBar.svelte @@ -0,0 +1,62 @@ + + + + + diff --git a/src/lib/layout/selection.svelte.js b/src/lib/layout/selection.svelte.js new file mode 100644 index 0000000..c6a0d7f --- /dev/null +++ b/src/lib/layout/selection.svelte.js @@ -0,0 +1,28 @@ +let selected = $state(new Set()); +let totalCountries = $state(0); + +export function toggle(id) { + const next = new Set(selected); + if (next.has(id)) { + next.delete(id); + } else { + next.add(id); + } + selected = next; +} + +export function clearAll() { + selected = new Set(); +} + +export function getSelected() { + return selected; +} + +export function setTotalCount(n) { + totalCountries = n; +} + +export function getTotalCount() { + return totalCountries; +} diff --git a/src/lib/shared/PhotoGallery.svelte b/src/lib/shared/PhotoGallery.svelte index 8eb37cf..aa14030 100644 --- a/src/lib/shared/PhotoGallery.svelte +++ b/src/lib/shared/PhotoGallery.svelte @@ -153,7 +153,7 @@ top: 14px; right: 14px; font-size: 12px; - font-weight: 500; + font-weight: 300; color: #fff; background: rgba(0,0,0,0.45); padding: 3px 10px; diff --git a/src/lib/timeline/JournalDetail.svelte b/src/lib/timeline/JournalDetail.svelte index e09bd2f..ac36318 100644 --- a/src/lib/timeline/JournalDetail.svelte +++ b/src/lib/timeline/JournalDetail.svelte @@ -82,7 +82,7 @@ align-items: center; gap: 6px; font-size: 14px; - font-weight: 500; + font-weight: 300; color: var(--text, #6b6375); background: none; border: none; @@ -91,7 +91,7 @@ margin-bottom: 28px; transition: color 0.15s; } - .back-btn:hover { color: var(--accent, #aa3bff); } + .back-btn:hover { color: var(--accent); } .hero-gallery-wrap { border-radius: 16px; @@ -110,17 +110,17 @@ .badge { font-size: 12px; - font-weight: 500; + font-weight: 300; padding: 4px 10px; border-radius: 20px; } - .loc-badge { background: var(--accent-bg, rgba(170,59,255,0.08)); color: var(--accent, #aa3bff); } + .loc-badge { background: var(--accent-bg); color: var(--accent); } .trip-badge--solo { background: rgba(245,158,11,0.12); color: #b45309; } .trip-badge--friends { background: rgba(59,130,246,0.12); color: #1d4ed8; } .detail-title { font-size: 28px; - font-weight: 700; + font-weight: 400; color: var(--text-h, #08060d); margin: 0 0 20px; letter-spacing: -0.6px; @@ -130,7 +130,7 @@ .stats-row { display: flex; align-items: center; gap: 20px; margin-bottom: 24px; } .stat { display: flex; flex-direction: column; gap: 2px; } .stat-label { font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text, #6b6375); } - .stat-value { font-size: 15px; font-weight: 600; color: var(--text-h, #08060d); } + .stat-value { font-size: 15px; font-weight: 300; color: var(--text-h, #08060d); } .stat-divider { width: 1px; height: 32px; background: var(--border, #e5e4e7); } .section-divider { border: none; border-top: 1px solid var(--border, #e5e4e7); margin: 24px 0; } @@ -140,13 +140,13 @@ .song-row { display: flex; align-items: center; gap: 14px; } .song-icon-wrap { width: 44px; height: 44px; border-radius: 50%; - background: var(--accent-bg, rgba(170,59,255,0.08)); - color: var(--accent, #aa3bff); + background: var(--accent-bg); + color: var(--accent); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .song-text { display: flex; flex-direction: column; gap: 2px; } .song-label { font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text, #6b6375); } - .song-name { font-size: 15px; font-weight: 600; color: var(--text-h, #08060d); } + .song-name { font-size: 15px; font-weight: 300; color: var(--text-h, #08060d); } .song-artist { font-size: 13px; color: var(--text, #6b6375); } @media (max-width: 600px) { diff --git a/src/lib/timeline/JournalSummary.svelte b/src/lib/timeline/JournalSummary.svelte new file mode 100644 index 0000000..de0de9d --- /dev/null +++ b/src/lib/timeline/JournalSummary.svelte @@ -0,0 +1,215 @@ + + +{#if stats} +
+ +

My Journey

+

{stats.yearRange}

+ +
+ + +
+
+ {stats.countries.length} + Countries +
+
+ {stats.cities.length} + Cities +
+
+ {stats.totalDays} + Days abroad +
+
+ {stats.tripCount} + Trips +
+
+ +
+ + +
+ Most visited + {stats.topCountry[0]} + {stats.topCountry[1]} {stats.topCountry[1] === 1 ? 'trip' : 'trips'} +
+ + +
+ Latest trip + {stats.latest.location.city} + {stats.latest.location.country} +
+ +
+ + +
+ Trip style +
+
+
+
+ {stats.soloPct}% Solo + {100 - stats.soloPct}% Friends +
+
+ +
+{/if} + + diff --git a/src/lib/timeline/TimelineCard.svelte b/src/lib/timeline/TimelineCard.svelte index 3af7554..21993ee 100644 --- a/src/lib/timeline/TimelineCard.svelte +++ b/src/lib/timeline/TimelineCard.svelte @@ -1,6 +1,4 @@
  • -
    -
    - - · - {entry.location.city}, {entry.location.country} - · - {entry.days} {entry.days === 1 ? 'day' : 'days'} -
    -
    e.key === 'Enter' && onClick()}> +
    e.key === 'Enter' && onClick()}> - - -
    -

    {entry.title}

    - {#if entry.memo} -

    {entry.memo}

    + +
    0}> +
    + {#if mainPhoto} + photo 1 + {:else} +
    {/if} -
    - - - - - - {entry.song.title} - · - {entry.song.artist} - - {entry.tripType === 'solo' ? 'Solo' : 'With Friends'} - + + +
    +
    + + {entry.tripType === 'solo' ? 'Solo' : 'With Friends'} + +
    +
    + {entry.location.city} + {entry.location.country} + {formatDate(entry.date)} · {entry.days} {entry.days === 1 ? 'day' : 'days'} +
    + + {#if thumbPhotos.length > 0} +
    + {#each thumbPhotos as photo, i} +
    + photo {i + 2} + {#if i === 2 && extraCount > 0} +
    +{extraCount}
    + {/if} +
    + {/each} +
    + {/if}
    +
  • diff --git a/src/lib/timeline/TimelineToolbar.svelte b/src/lib/timeline/TimelineToolbar.svelte index 93900ec..3e173b1 100644 --- a/src/lib/timeline/TimelineToolbar.svelte +++ b/src/lib/timeline/TimelineToolbar.svelte @@ -41,13 +41,13 @@ font-size: 11px; letter-spacing: 3px; text-transform: uppercase; - color: var(--accent, #aa3bff); + color: var(--accent); margin: 0 0 6px; } .page-title { font-size: 32px; - font-weight: 700; + font-weight: 400; color: var(--text-h, #08060d); margin: 0; letter-spacing: -0.8px; @@ -69,7 +69,7 @@ background-repeat: no-repeat; background-position: right 10px center; } - select:focus { outline: 2px solid var(--accent, #aa3bff); outline-offset: 2px; } + select:focus { outline: 2px solid var(--accent); outline-offset: 2px; } @media (max-width: 600px) { .page-title { font-size: 26px; } diff --git a/src/lib/timeline/TimelineView.svelte b/src/lib/timeline/TimelineView.svelte index cb54b78..4d9f541 100644 --- a/src/lib/timeline/TimelineView.svelte +++ b/src/lib/timeline/TimelineView.svelte @@ -4,6 +4,7 @@ import TimelineToolbar from './TimelineToolbar.svelte'; import TimelineCard from './TimelineCard.svelte'; import JournalDetail from './JournalDetail.svelte'; + import JournalSummary from './JournalSummary.svelte'; /** @type {import('../stores/journalStore.js').JournalEntry|null} */ let selected = $state(null); @@ -27,38 +28,86 @@ return 0; }); }); + + function getYear(iso) { + return new Date(iso).getFullYear(); + } -{#if selected} - (selected = null)} /> -{:else} -
    - (sortKey = k)} /> +
    - {#if sortedEntries.length === 0} -

    No journal entries yet.

    - {:else} -
      - {#each sortedEntries as entry (entry.id)} - (selected = entry)} /> - {/each} -
    - {/if} + {#if selected} + +
    + (selected = null)} /> +
    + {:else} + + -
    - {sortedEntries.length} {sortedEntries.length === 1 ? 'entry' : 'entries'} -
    -
    -{/if} +
    + (sortKey = k)} /> + + {#if sortedEntries.length === 0} +

    No journal entries yet.

    + {:else} +
      + {#each sortedEntries as entry, i (entry.id)} + {#if i === 0 || getYear(entry.date) !== getYear(sortedEntries[i - 1].date)} + + {/if} + (selected = entry)} /> + {/each} +
    + {/if} + +
    + {sortedEntries.length} {sortedEntries.length === 1 ? 'entry' : 'entries'} +
    +
    + {/if} + + diff --git a/src/lib/world-map/StatsPanel.svelte b/src/lib/world-map/StatsPanel.svelte new file mode 100644 index 0000000..cdfe792 --- /dev/null +++ b/src/lib/world-map/StatsPanel.svelte @@ -0,0 +1,307 @@ + + +
    + + + {#if !collapsed} +
    +

    your statistics

    + + visited countries +
    +
    +
    +
    + {total} / {grandTotal} +
    + +
    + + by continent + {#each CONTINENTS as continent} + {@const contTotal = continentTotals[continent]} +
    + + {continent} + {counts[continent]}/{contTotal} +
    + {/each} + +
    + {#if segments.length > 0} + + {#each segments as seg} + + + {seg.cont} + + {/each} + + + {:else} + + + + + {/if} +
    + +
    + +
    Contains all UN countries, Kosovo, Hong Kong and Taiwan
    +
    + {/if} +
    + + diff --git a/src/lib/world-map/WorldMap.svelte b/src/lib/world-map/WorldMap.svelte new file mode 100644 index 0000000..46571f4 --- /dev/null +++ b/src/lib/world-map/WorldMap.svelte @@ -0,0 +1,159 @@ + + +
    + + diff --git a/src/lib/world-map/continents.js b/src/lib/world-map/continents.js new file mode 100644 index 0000000..7a5ad24 --- /dev/null +++ b/src/lib/world-map/continents.js @@ -0,0 +1,212 @@ +export const CONTINENTS = ['Europe', 'Asia', 'Africa', 'N. America', 'S. America', 'Oceania']; + +const map = { + '004': 'Asia', // Afghanistan + '008': 'Europe', // Albania + '012': 'Africa', // Algeria + '020': 'Europe', // Andorra + '024': 'Africa', // Angola + '028': 'N. America', // Antigua and Barb. + '031': 'Asia', // Azerbaijan + '032': 'S. America', // Argentina + '036': 'Oceania', // Australia + '040': 'Europe', // Austria + '044': 'N. America', // Bahamas + '048': 'Asia', // Bahrain + '050': 'Asia', // Bangladesh + '051': 'Asia', // Armenia + '052': 'N. America', // Barbados + '056': 'Europe', // Belgium + '064': 'Asia', // Bhutan + '068': 'S. America', // Bolivia + '070': 'Europe', // Bosnia and Herz. + '072': 'Africa', // Botswana + '076': 'S. America', // Brazil + '084': 'N. America', // Belize + '090': 'Oceania', // Solomon Is. + '096': 'Asia', // Brunei + '100': 'Europe', // Bulgaria + '104': 'Asia', // Myanmar + '108': 'Africa', // Burundi + '112': 'Europe', // Belarus + '116': 'Asia', // Cambodia + '120': 'Africa', // Cameroon + '124': 'N. America', // Canada + '132': 'Africa', // Cabo Verde + '140': 'Africa', // Central African Rep. + '144': 'Asia', // Sri Lanka + '148': 'Africa', // Chad + '152': 'S. America', // Chile + '156': 'Asia', // China + '158': 'Asia', // Taiwan + '170': 'S. America', // Colombia + '174': 'Africa', // Comoros + '178': 'Africa', // Congo + '180': 'Africa', // Dem. Rep. Congo + '188': 'N. America', // Costa Rica + '191': 'Europe', // Croatia + '192': 'N. America', // Cuba + '196': 'Asia', // Cyprus + '203': 'Europe', // Czechia + '204': 'Africa', // Benin + '208': 'Europe', // Denmark + '212': 'N. America', // Dominica + '214': 'N. America', // Dominican Rep. + '218': 'S. America', // Ecuador + '222': 'N. America', // El Salvador + '226': 'Africa', // Eq. Guinea + '231': 'Africa', // Ethiopia + '232': 'Africa', // Eritrea + '233': 'Europe', // Estonia + '242': 'Oceania', // Fiji + '246': 'Europe', // Finland + '250': 'Europe', // France + '262': 'Africa', // Djibouti + '266': 'Africa', // Gabon + '268': 'Asia', // Georgia + '270': 'Africa', // Gambia + '275': 'Asia', // Palestine + '276': 'Europe', // Germany + '288': 'Africa', // Ghana + '296': 'Oceania', // Kiribati + '300': 'Europe', // Greece + '308': 'N. America', // Grenada + '320': 'N. America', // Guatemala + '324': 'Africa', // Guinea + '328': 'S. America', // Guyana + '332': 'N. America', // Haiti + '336': 'Europe', // Vatican + '340': 'N. America', // Honduras + '344': 'Asia', // Hong Kong + '348': 'Europe', // Hungary + '352': 'Europe', // Iceland + '356': 'Asia', // India + '360': 'Asia', // Indonesia + '364': 'Asia', // Iran + '368': 'Asia', // Iraq + '372': 'Europe', // Ireland + '376': 'Asia', // Israel + '380': 'Europe', // Italy + '384': 'Africa', // Cote d'Ivoire + '388': 'N. America', // Jamaica + '392': 'Asia', // Japan + '398': 'Asia', // Kazakhstan + '400': 'Asia', // Jordan + '404': 'Africa', // Kenya + '408': 'Asia', // North Korea + '410': 'Asia', // South Korea + '414': 'Asia', // Kuwait + '417': 'Asia', // Kyrgyzstan + '418': 'Asia', // Laos + '422': 'Asia', // Lebanon + '426': 'Africa', // Lesotho + '428': 'Europe', // Latvia + '430': 'Africa', // Liberia + '434': 'Africa', // Libya + '438': 'Europe', // Liechtenstein + '440': 'Europe', // Lithuania + '442': 'Europe', // Luxembourg + '450': 'Africa', // Madagascar + '454': 'Africa', // Malawi + '458': 'Asia', // Malaysia + '462': 'Asia', // Maldives + '466': 'Africa', // Mali + '470': 'Europe', // Malta + '478': 'Africa', // Mauritania + '480': 'Africa', // Mauritius + '484': 'N. America', // Mexico + '492': 'Europe', // Monaco + '496': 'Asia', // Mongolia + '498': 'Europe', // Moldova + '499': 'Europe', // Montenegro + '504': 'Africa', // Morocco + '508': 'Africa', // Mozambique + '512': 'Asia', // Oman + '516': 'Africa', // Namibia + '520': 'Oceania', // Nauru + '524': 'Asia', // Nepal + '528': 'Europe', // Netherlands + '548': 'Oceania', // Vanuatu + '554': 'Oceania', // New Zealand + '558': 'N. America', // Nicaragua + '562': 'Africa', // Niger + '566': 'Africa', // Nigeria + '578': 'Europe', // Norway + '583': 'Oceania', // Micronesia + '584': 'Oceania', // Marshall Is. + '585': 'Oceania', // Palau + '586': 'Asia', // Pakistan + '591': 'N. America', // Panama + '598': 'Oceania', // Papua New Guinea + '600': 'S. America', // Paraguay + '604': 'S. America', // Peru + '608': 'Asia', // Philippines + '616': 'Europe', // Poland + '620': 'Europe', // Portugal + '624': 'Africa', // Guinea-Bissau + '626': 'Asia', // Timor-Leste + '634': 'Asia', // Qatar + '642': 'Europe', // Romania + '643': 'Europe', // Russia + '646': 'Africa', // Rwanda + '659': 'N. America', // St. Kitts and Nevis + '662': 'N. America', // Saint Lucia + '670': 'N. America', // St. Vin. and Gren. + '674': 'Europe', // San Marino + '678': 'Africa', // Sao Tome and Principe + '682': 'Asia', // Saudi Arabia + '686': 'Africa', // Senegal + '688': 'Europe', // Serbia + '690': 'Africa', // Seychelles + '694': 'Africa', // Sierra Leone + '702': 'Asia', // Singapore + '703': 'Europe', // Slovakia + '704': 'Asia', // Vietnam + '705': 'Europe', // Slovenia + '706': 'Africa', // Somalia + '710': 'Africa', // South Africa + '716': 'Africa', // Zimbabwe + '724': 'Europe', // Spain + '728': 'Africa', // S. Sudan + '729': 'Africa', // Sudan + '732': 'Africa', // W. Sahara + '740': 'S. America', // Suriname + '748': 'Africa', // eSwatini + '752': 'Europe', // Sweden + '756': 'Europe', // Switzerland + '760': 'Asia', // Syria + '762': 'Asia', // Tajikistan + '764': 'Asia', // Thailand + '768': 'Africa', // Togo + '776': 'Oceania', // Tonga + '780': 'N. America', // Trinidad and Tobago + '784': 'Asia', // United Arab Emirates + '788': 'Africa', // Tunisia + '792': 'Asia', // Turkey + '795': 'Asia', // Turkmenistan + '800': 'Africa', // Uganda + '804': 'Europe', // Ukraine + '807': 'Europe', // Macedonia + '818': 'Africa', // Egypt + '826': 'Europe', // United Kingdom + '834': 'Africa', // Tanzania + '840': 'N. America', // United States of America + '854': 'Africa', // Burkina Faso + '858': 'S. America', // Uruguay + '860': 'Asia', // Uzbekistan + '862': 'S. America', // Venezuela + '882': 'Oceania', // Samoa + '887': 'Asia', // Yemen + '894': 'Africa', // Zambia + 'XK': 'Europe', // Kosovo +}; + +export const continentTotals = CONTINENTS.reduce((acc, c) => (acc[c] = 0, acc), {}); +for (const id of Object.keys(map)) { + const cont = map[id]; + if (cont) continentTotals[cont]++; +} + +export function getContinent(id) { + return map[id] ?? null; +}