react rewrite

This commit is contained in:
2024-10-25 18:39:38 +02:00
parent 8c31799674
commit 2bd6e392d4
107 changed files with 736 additions and 751 deletions
+24 -1
View File
@@ -1 +1,24 @@
htmlmap.html # Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
-5
View File
@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
Generated
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
</project> </project>
+1 -22
View File
@@ -1,25 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectTasksOptions"> <component name="ProjectTasksOptions" suppressed-tasks="SCSS" />
<TaskOptions isEnabled="true">
<option name="arguments" value="$FileName$:$FileNameWithoutExtension$.css" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="scss" />
<option name="immediateSync" value="true" />
<option name="name" value="SCSS" />
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="sass" />
<option name="runOnExternalChanges" value="true" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="$FileDir$" />
<envs />
</TaskOptions>
</component>
</project> </project>
Executable
BIN
View File
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
# Ignore all CSS files
*.css
# Ignore all CSS map files
*.css.map
-128
View File
@@ -1,128 +0,0 @@
/* crimson-pro-200 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 200;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-200italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 200;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-200italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 300;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 300;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 400;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 400;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 500;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 500;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 600;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-600italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 600;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 700;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 700;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-800 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 800;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-800.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-800italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 800;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-800italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-900 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: normal;
font-weight: 900;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-900.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* crimson-pro-900italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Crimson Pro';
font-style: italic;
font-weight: 900;
src: url('../../fonts/crimson_pro/crimson-pro-v24-latin-900italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
+28
View File
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
+6 -17
View File
@@ -1,8 +1,9 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Interactive Tensei Shitara Slime Datta Ken Map</title> <title>Interactive Tensei Shitara Slime Datta Ken Map</title>
<meta name="description" content="Interactive map of the central world of Tensei Shitara Slime Datta Ken (That Time I Got Reincarnated as a Slime)"> <meta name="description" content="Interactive map of the central world of Tensei Shitara Slime Datta Ken (That Time I Got Reincarnated as a Slime)">
@@ -29,21 +30,9 @@
<meta name="twitter:title" content="Interactive Tensei Shitara Slime Datta Ken Map" /> <meta name="twitter:title" content="Interactive Tensei Shitara Slime Datta Ken Map" />
<meta name="twitter:description" content="Interactive map of the central world of Tensei Shitara Slime Datta Ken (That Time I Got Reincarnated as a Slime)" /> <meta name="twitter:description" content="Interactive map of the central world of Tensei Shitara Slime Datta Ken (That Time I Got Reincarnated as a Slime)" />
<meta name="twitter:image" content="/img/twitterImage.png" /> <meta name="twitter:image" content="/img/twitterImage.png" />
<link href="css/styles.css" rel="stylesheet">
</head> </head>
<body> <body>
<div id="root"></div>
<svg id="map" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2641 2035"></svg> <script type="module" src="/src/main.tsx"></script>
<div id="tooltip" class="tooltip"></div>
<div class="legend">
<h1>Interactive Map of the Magic Continent</h1>
<div class="border"></div>
</div>
<script src="js/mapBuilder.js" type="module"></script>
<script src="js/tooltip.js"></script>
</body> </body>
</html> </html>
-167
View File
@@ -1,167 +0,0 @@
/**
* Map class for creating interactive maps with SVG
*/
export default class Map {
/**
* @param {string} svgId - The ID of the SVG element
* @param {string} mapImage - The URL of the map image
*/
constructor(svgId, mapImage) {
this.svg = document.getElementById(svgId);
this.svg.innerHTML = "";
this.g = document.createElementNS("http://www.w3.org/2000/svg", "g");
this.svg.appendChild(this.g);
this.g.innerHTML += `<image href="${mapImage}" width="100%"/>`;
this.isDragging = false;
this.startX = 0;
this.startY = 0;
this.initialTranslateX = 0;
this.initialTranslateY = 0;
this.initialScale = 1;
this.dragSensitivity = 2;
this.maxScale = 6;
this.minScale = 1;
this.initializeEvents();
}
initializeEvents() {
this.svg.addEventListener("mousedown", (e) => this.onMouseDown(e));
this.svg.addEventListener("mousemove", (e) => this.onMouseMove(e));
this.svg.addEventListener("mouseup", () => this.onMouseUp());
this.svg.addEventListener("mouseleave", () => this.onMouseUp());
this.svg.addEventListener("wheel", (e) => this.onWheel(e));
}
/**
* Set the zoom level
* @param {number} zoomLevel - The zoom level
*/
setZoomLevel(zoomLevel) {
const svgRect = this.svg.getBoundingClientRect();
const centerX = svgRect.width / 2;
const centerY = svgRect.height / 2;
const [translate, scale] = this.parseTransform(this.g.getAttribute("transform") || "translate(0,0) scale(1)");
const newScale = Math.min(Math.max(zoomLevel, this.minScale), this.maxScale);
const svgPoint = this.svg.createSVGPoint();
svgPoint.x = centerX;
svgPoint.y = centerY;
const centerPoint = svgPoint.matrixTransform(this.svg.getScreenCTM().inverse());
const newTranslateX = translate[0] - (centerPoint.x - translate[0]) * (newScale / scale - 1);
const newTranslateY = translate[1] - (centerPoint.y - translate[1]) * (newScale / scale - 1);
this.g.setAttribute("transform", `translate(${newTranslateX}, ${newTranslateY}) scale(${newScale})`);
}
/**
* Zoom in
* @param factor - The zoom factor
*/
zoomIn(factor = 1.1) {
const [translate, scale] = this.parseTransform(this.g.getAttribute("transform") || "translate(0,0) scale(1)");
const newScale = Math.min(scale * factor, this.maxScale);
this.setZoomLevel(newScale);
}
/**
* Zoom out
* @param {number} factor - The zoom factor
*/
zoomOut(factor = 0.9) {
const [translate, scale] = this.parseTransform(this.g.getAttribute("transform") || "translate(0,0) scale(1)");
const newScale = Math.max(scale * factor, this.minScale);
this.setZoomLevel(newScale);
}
onMouseDown(e) {
if (!this.g.getAttribute("transform") || this.g.getAttribute("transform").includes("scale(1)")) return;
this.isDragging = true;
this.startX = e.clientX;
this.startY = e.clientY;
const [translate, scale] = this.parseTransform(this.g.getAttribute("transform") || "translate(0,0) scale(1)");
this.initialTranslateX = translate[0];
this.initialTranslateY = translate[1];
this.initialScale = scale;
}
onMouseMove(e) {
if (!this.isDragging) return;
const svgRect = this.svg.getBoundingClientRect();
const mapRect = this.g.getBBox();
const deltaX = (e.clientX - this.startX) * this.dragSensitivity;
const deltaY = (e.clientY - this.startY) * this.dragSensitivity;
let newTranslateX = this.initialTranslateX + deltaX;
let newTranslateY = this.initialTranslateY + deltaY;
const scale = this.initialScale;
const mapWidth = mapRect.width * scale;
const mapHeight = mapRect.height * scale;
const svgWidth = svgRect.width;
const svgHeight = svgRect.height;
const minTranslateX = Math.min(0, svgWidth - mapWidth);
const minTranslateY = Math.min(0, svgHeight - mapHeight);
const maxTranslateX = 0;
const maxTranslateY = 0;
newTranslateX = Math.max(minTranslateX, Math.min(maxTranslateX, newTranslateX));
newTranslateY = Math.max(minTranslateY, Math.min(maxTranslateY, newTranslateY));
this.g.setAttribute("transform", `translate(${newTranslateX}, ${newTranslateY}) scale(${scale})`);
}
onMouseUp() {
this.isDragging = false;
}
onWheel(e) {
e.preventDefault();
const [translate, scale] = this.parseTransform(this.g.getAttribute("transform") || "translate(0,0) scale(1)");
const newScale = Math.min(Math.max(scale * (e.deltaY > 0 ? 0.9 : 1.1), 1), this.maxScale);
if (newScale === 1) {
this.g.setAttribute("transform", `translate(0,0) scale(1)`);
} else {
const svgPoint = this.svg.createSVGPoint();
svgPoint.x = e.clientX;
svgPoint.y = e.clientY;
const mousePoint = svgPoint.matrixTransform(this.svg.getScreenCTM().inverse());
const newTranslateX = translate[0] - (mousePoint.x - translate[0]) * (newScale / scale - 1);
const newTranslateY = translate[1] - (mousePoint.y - translate[1]) * (newScale / scale - 1);
this.g.setAttribute("transform", `translate(${newTranslateX}, ${newTranslateY}) scale(${newScale})`);
}
}
parseTransform(transform) {
const translateMatch = transform.match(/translate\(([^)]+)\)/);
const scaleMatch = transform.match(/scale\(([^)]+)\)/);
const translate = translateMatch ? translateMatch[1].split(",").map(Number) : [0, 0];
const scale = scaleMatch ? parseFloat(scaleMatch[1]) : 1;
return [translate, scale];
}
addPolygon(points, attributes = {}) {
const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
polygon.setAttribute("points", points);
Object.entries(attributes).forEach(([key, value]) => polygon.setAttribute(key, value));
this.g.appendChild(polygon);
}
addSVGElement(svgString) {
this.g.innerHTML += svgString;
}
}
-109
View File
@@ -1,109 +0,0 @@
import Map from "./Map.js";
export default class SlimeMap extends Map {
/**
* @param {string} svgId - The ID of the SVG element
* @param {string} mapImage - The URL of the map image
* @param nations
* @param capitals
* @param pois
* @param cities
*/
constructor(svgId, mapImage, nations, capitals, pois, cities) {
super(svgId, mapImage);
this.nations = nations;
this.capitals = capitals;
this.pois = pois;
this.cities = cities;
this.addNations();
this.addCapitals();
this.addPOIs();
this.addCities();
}
addNations() {
for (let nation of this.nations) {
this.addPolygon(nation.points, {
class: "region",
fill: "transparent",
stroke: "transparent",
"stroke-width": "4",
"data-name": nation.name,
"data-ruler": nation.ruler,
"data-capital": nation.capital,
"data-population": nation.population,
"data-description": nation.description,
"data-url": nation.url ?? ""
});
}
}
addCapitals() {
for (let capital of this.capitals) {
const svgString = `
<g transform="translate(${capital.position.x}, ${capital.position.y}) scale(2.5, 2.5)" fill="transparent"
class="location"
data-name="${capital.name}"
data-url="${capital.url ?? ""}"
data-description="${capital.description ?? ""}"
data-image-url="${capital.image?.url ?? ""}"
data-image-name="${capital.image?.name ?? ""}"
data-image-credit="${capital.image?.credit ?? ""}">
<rect x="0" y="0" width="24" height="24" fill="transparent" stroke="transparent" stroke-width="4" />
<!-- Black outer stroke -->
<path d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14"
stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
<!-- White inner stroke -->
<path d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14"
stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</g>`;
this.addSVGElement(svgString);
}
}
addCities() {
for (let city of this.cities) {
const svgString = `
<g transform="translate(${city.position.x}, ${city.position.y}) scale(2.5, 2.5)" fill="transparent"
class="location"
data-name="${city.name}"
data-url="${city.url ?? ""}"
data-description="${city.description ?? ""}"
data-image-url="${city.image?.url ?? ""}"
data-image-name="${city.image?.name ?? ""}"
data-image-credit="${city.image?.credit ?? ""}">
<rect x="0" y="0" width="24" height="24" fill="transparent" stroke="transparent" stroke-width="4" />
<!-- Black border -->
<path d="M15 3L3 19V21H21V19L9 3M12 15L16 21H8L12 15Z"
stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" transform="scale(.8, .8)"></path>
<!-- White inner stroke -->
<path d="M15 3L3 19V21H21V19L9 3M12 15L16 21H8L12 15Z"
stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" transform="scale(.8, .8)"></path>
</g>`;
this.addSVGElement(svgString);
}
}
addPOIs() {
for (let poi of this.pois) {
const svgString = `
<g transform="translate(${poi.position.x}, ${poi.position.y}) scale(2, 2)" fill="transparent"
class="location"
data-name="${poi.name}"
data-description="${poi.description}"
data-url="${poi.url ?? ""}"
data-image-url="${poi.image?.url ?? ""}"
data-image-name="${poi.image?.name ?? ""}"
data-image-credit="${poi.image?.credit ?? ""}">
<rect width="24" height="24" fill="transparent" stroke="transparent" stroke-width="4" />
<path d="M11.2691 4.41115C11.5006 3.89177 11.6164 3.63208 11.7776 3.55211C11.9176 3.48263 12.082 3.48263 12.222 3.55211C12.3832 3.63208 12.499 3.89177 12.7305 4.41115L14.5745 8.54808C14.643 8.70162 14.6772 8.77839 14.7302 8.83718C14.777 8.8892 14.8343 8.93081 14.8982 8.95929C14.9705 8.99149 15.0541 9.00031 15.2213 9.01795L19.7256 9.49336C20.2911 9.55304 20.5738 9.58288 20.6997 9.71147C20.809 9.82316 20.8598 9.97956 20.837 10.1342C20.8108 10.3122 20.5996 10.5025 20.1772 10.8832L16.8125 13.9154C16.6877 14.0279 16.6252 14.0842 16.5857 14.1527C16.5507 14.2134 16.5288 14.2807 16.5215 14.3503C16.5132 14.429 16.5306 14.5112 16.5655 14.6757L17.5053 19.1064C17.6233 19.6627 17.6823 19.9408 17.5989 20.1002C17.5264 20.2388 17.3934 20.3354 17.2393 20.3615C17.0619 20.3915 16.8156 20.2495 16.323 19.9654L12.3995 17.7024C12.2539 17.6184 12.1811 17.5765 12.1037 17.56C12.0352 17.5455 11.9644 17.5455 11.8959 17.56C11.8185 17.5765 11.7457 17.6184 11.6001 17.7024L7.67662 19.9654C7.18404 20.2495 6.93775 20.3915 6.76034 20.3615C6.60623 20.3354 6.47319 20.2388 6.40075 20.1002C6.31736 19.9408 6.37635 19.6627 6.49434 19.1064L7.4341 14.6757C7.46898 14.5112 7.48642 14.429 7.47814 14.3503C7.47081 14.2807 7.44894 14.2134 7.41394 14.1527C7.37439 14.0842 7.31195 14.0279 7.18708 13.9154L3.82246 10.8832C3.40005 10.5025 3.18884 10.3122 3.16258 10.1342C3.13978 9.97956 3.19059 9.82316 3.29993 9.71147C3.42581 9.58288 3.70856 9.55304 4.27406 9.49336L8.77835 9.01795C8.94553 9.00031 9.02911 8.99149 9.10139 8.95929C9.16534 8.93081 9.2226 8.8892 9.26946 8.83718C9.32241 8.77839 9.35663 8.70162 9.42508 8.54808L11.2691 4.41115Z"
stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M11.2691 4.41115C11.5006 3.89177 11.6164 3.63208 11.7776 3.55211C11.9176 3.48263 12.082 3.48263 12.222 3.55211C12.3832 3.63208 12.499 3.89177 12.7305 4.41115L14.5745 8.54808C14.643 8.70162 14.6772 8.77839 14.7302 8.83718C14.777 8.8892 14.8343 8.93081 14.8982 8.95929C14.9705 8.99149 15.0541 9.00031 15.2213 9.01795L19.7256 9.49336C20.2911 9.55304 20.5738 9.58288 20.6997 9.71147C20.809 9.82316 20.8598 9.97956 20.837 10.1342C20.8108 10.3122 20.5996 10.5025 20.1772 10.8832L16.8125 13.9154C16.6877 14.0279 16.6252 14.0842 16.5857 14.1527C16.5507 14.2134 16.5288 14.2807 16.5215 14.3503C16.5132 14.429 16.5306 14.5112 16.5655 14.6757L17.5053 19.1064C17.6233 19.6627 17.6823 19.9408 17.5989 20.1002C17.5264 20.2388 17.3934 20.3354 17.2393 20.3615C17.0619 20.3915 16.8156 20.2495 16.323 19.9654L12.3995 17.7024C12.2539 17.6184 12.1811 17.5765 12.1037 17.56C12.0352 17.5455 11.9644 17.5455 11.8959 17.56C11.8185 17.5765 11.7457 17.6184 11.6001 17.7024L7.67662 19.9654C7.18404 20.2495 6.93775 20.3915 6.76034 20.3615C6.60623 20.3354 6.47319 20.2388 6.40075 20.1002C6.31736 19.9408 6.37635 19.6627 6.49434 19.1064L7.4341 14.6757C7.46898 14.5112 7.48642 14.429 7.47814 14.3503C7.47081 14.2807 7.44894 14.2134 7.41394 14.1527C7.37439 14.0842 7.31195 14.0279 7.18708 13.9154L3.82246 10.8832C3.40005 10.5025 3.18884 10.3122 3.16258 10.1342C3.13978 9.97956 3.19059 9.82316 3.29993 9.71147C3.42581 9.58288 3.70856 9.55304 4.27406 9.49336L8.77835 9.01795C8.94553 9.00031 9.02911 8.99149 9.10139 8.95929C9.16534 8.93081 9.2226 8.8892 9.26946 8.83718C9.32241 8.77839 9.35663 8.70162 9.42508 8.54808L11.2691 4.41115Z"
stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
<!-- <polygon points="0,-10 3,-3 10,0 3,3 0,10 -3,3 -10,0 -3,-3"-->
<!-- fill="white" stroke="black" stroke-width="1" />-->
</g>`;
this.addSVGElement(svgString);
}
}
}
-4
View File
@@ -1,4 +0,0 @@
export * from "./pois.js";
export * from "./nations.js";
export * from "./capitals.js";
export * from "./cities.js";
-4
View File
@@ -1,4 +0,0 @@
import {pois, capitals, nations, cities} from "./locations";
import SlimeMap from "./SlimeMap.js";
const slimeMap = new SlimeMap("map", "img/map.webp", nations, capitals, pois, cities);
-171
View File
@@ -1,171 +0,0 @@
document.addEventListener("DOMContentLoaded", () => {
const tooltip = document.getElementById('tooltip');
let isControlHeld = false;
let mouseOnTooltipableArea = false;
let currentTooltipContent = '';
setInterval(() => {
console.log("Control is held:", isControlHeld);
}, 500)
const showTooltip = (content, e) => {
mouseOnTooltipableArea = true;
currentTooltipContent = content;
// console.log("Set currentTooltipContent to", currentTooltipContent);
if (isControlHeld) return;
tooltip.innerHTML = content;
tooltip.style.display = 'flex';
positionTooltip(e);
};
const hideTooltip = () => {
mouseOnTooltipableArea = false;
currentTooltipContent = '';
// console.log("Set currentTooltipContent to", currentTooltipContent);
if (isControlHeld) return;
tooltip.style.display = 'none';
};
const positionTooltip = (e) => {
if (isControlHeld) return;
tooltip.innerHTML = currentTooltipContent;
if (currentTooltipContent) tooltip.style.display = 'flex';
const tooltipWidth = tooltip.offsetWidth;
const tooltipHeight = tooltip.offsetHeight;
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// Default positioning (to the right and below the cursor)
let tooltipX = e.pageX + 10;
let tooltipY = e.pageY + 10;
// Horizontal Overflow (Check if tooltip overflows on the right side)
if (tooltipX + tooltipWidth > screenWidth) {
tooltipX = e.pageX - tooltipWidth - 10;
}
// Vertical Overflow (Check if tooltip overflows at the bottom)
if (tooltipY + tooltipHeight > screenHeight) {
tooltipY = e.pageY - tooltipHeight - 10;
}
tooltip.style.left = `${tooltipX}px`;
tooltip.style.top = `${tooltipY}px`;
};
const attachTooltipHandlers = (elements, getContentCallback) => {
elements.forEach(element => {
element.addEventListener('mouseover', (e) => {
const content = getContentCallback(element);
showTooltip(content, e);
});
element.addEventListener('mousemove', positionTooltip);
element.addEventListener('mouseout', hideTooltip);
});
};
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) isControlHeld = true;
});
document.addEventListener('keyup', (e) => {
if (!e.ctrlKey && !e.metaKey) {
isControlHeld = false;
// if (!mouseOnTooltipableArea) hideTooltip();
}
});
document.addEventListener('mousemove', (e) => {
// console.log("IsControlHeld", isControlHeld);
// console.log("MouseOnTooltipableArea", mouseOnTooltipableArea);
if (!isControlHeld && !mouseOnTooltipableArea) {
hideTooltip();
}
});
const locations = document.querySelectorAll('.location');
attachTooltipHandlers(locations, getLocationTooltip);
const regions = document.querySelectorAll('.region');
attachTooltipHandlers(regions, getRegionTooltip);
});
/**
* @typedef {Object} RegionData
* @property {string} name
* @property {string} capital
* @property {string} description
* @property {string} ruler
* @property {string} population
*/
/**
* Get region tooltip
* @param {Element} element
* @return {string}
*/
function getRegionTooltip(element) {
const regionName = element.getAttribute('data-name');
const regionPopulation = element.getAttribute('data-population');
const regionCapital = element.getAttribute('data-capital');
const regionDescription = element.getAttribute('data-description');
const regionRuler = element.getAttribute('data-ruler');
const url = element.getAttribute('data-url');
// let data = url ? `<a href="${url}" class="titlelink" target="_blank" rel="noreferrer noopener"><h3>${regionName}</h3></a>` : `<h3>${regionName}</h3>`;
let data = `<h3>${regionName}</h3>`;
data += `<div class="border"></div>`;
if (regionCapital) data += `
<div class="detailbox">
<svg title="wsda" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
<span>${regionCapital}</span>
</div>
`;
if (regionPopulation) data += `
<div class="detailbox">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M13 20V18C13 15.2386 10.7614 13 8 13C5.23858 13 3 15.2386 3 18V20H13ZM13 20H21V19C21 16.0545 18.7614 14 16 14C14.5867 14 13.3103 14.6255 12.4009 15.6311M11 7C11 8.65685 9.65685 10 8 10C6.34315 10 5 8.65685 5 7C5 5.34315 6.34315 4 8 4C9.65685 4 11 5.34315 11 7ZM18 9C18 10.1046 17.1046 11 16 11C14.8954 11 14 10.1046 14 9C14 7.89543 14.8954 7 16 7C17.1046 7 18 7.89543 18 9Z" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
<span>${regionPopulation}</span>
</div>
`;
if (regionRuler) data += `
<div class="detailbox">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M4 8L6 20H18L20 8M4 8L5.71624 9.37299C6.83218 10.2657 7.39014 10.7121 7.95256 10.7814C8.4453 10.8421 8.94299 10.7173 9.34885 10.4314C9.81211 10.1051 10.0936 9.4483 10.6565 8.13476L12 5M4 8C4.55228 8 5 7.55228 5 7C5 6.44772 4.55228 6 4 6C3.44772 6 3 6.44772 3 7C3 7.55228 3.44772 8 4 8ZM20 8L18.2838 9.373C17.1678 10.2657 16.6099 10.7121 16.0474 10.7814C15.5547 10.8421 15.057 10.7173 14.6511 10.4314C14.1879 10.1051 13.9064 9.4483 13.3435 8.13476L12 5M20 8C20.5523 8 21 7.55228 21 7C21 6.44772 20.5523 6 20 6C19.4477 6 19 6.44772 19 7C19 7.55228 19.4477 8 20 8ZM12 5C12.5523 5 13 4.55228 13 4C13 3.44772 12.5523 3 12 3C11.4477 3 11 3.44772 11 4C11 4.55228 11.4477 5 12 5ZM12 4H12.01M20 7H20.01M4 7H4.01" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
<span>${regionRuler}</span>
</div>
`;
if (regionDescription) data += `
<div class="detailbox">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M3 10H16M3 14H21M3 18H16M3 6H21" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>
<span>${regionDescription}</span>
</div>
`;
if (url) data += `<a href="${url}" class="icon" target="_blank" rel="noreferrer noopener" class="more"><img src="img/icons/book.svg">Wiki</a>`;
return data;
}
function getLocationTooltip(location) {
const locationName = location.getAttribute('data-name');
const locationDescription = location.getAttribute('data-description');
const imageUrl = location.getAttribute('data-image-url');
const imageName = location.getAttribute('data-image-name');
const imageCredit = location.getAttribute('data-image-credit');
const url = location.getAttribute('data-url');
// let locationString = url ? `<a href="${url}" class="titlelink" target="_blank" rel="noreferrer noopener"><h3>${locationName}</h3></a>` : `<h3>${locationName}</h3>`;
let locationString = `<h3>${locationName}</h3>`;
if (locationDescription || imageUrl) locationString += `<div class="border"></div>`;
if (locationDescription) locationString += `<span>${locationDescription}</span>`;
if (imageUrl) locationString += `<img class="locationimg" src="${imageUrl}" alt="${imageName ?? locationName}" title="${imageCredit ?? ""}">`;
if (url) locationString += `<a href="${url}" class="icon" target="_blank" rel="noreferrer noopener" class="more"><img src="img/icons/book.svg" alt="wiki icon">Wiki</a>`;
return locationString;
}
+32
View File
@@ -0,0 +1,32 @@
{
"name": "slime_map",
"private": true,
"version": "0.0.0",
"type": "module",
"license": "GNU General Public License v3.0",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.27.0"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.13",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"typescript-eslint": "^8.10.0",
"vite": "^5.4.9",
"sass": "^1.80.4"
}
}

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Before

Width:  |  Height:  |  Size: 971 B

After

Width:  |  Height:  |  Size: 971 B

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 452 B

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 873 B

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File
+15
View File
@@ -0,0 +1,15 @@
import './App.scss'
import {Routes, BrowserRouter as Router, Route} from "react-router-dom";
import Main from "./pages/Main.tsx";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Main />} />
</Routes>
</Router>
)
}
export default App
@@ -4,7 +4,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-300italic - latin */ /* cormorant-garamond-300italic - latin */
@font-face { @font-face {
@@ -12,7 +12,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: italic; font-style: italic;
font-weight: 300; font-weight: 300;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-regular - latin */ /* cormorant-garamond-regular - latin */
@font-face { @font-face {
@@ -20,7 +20,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-italic - latin */ /* cormorant-garamond-italic - latin */
@font-face { @font-face {
@@ -28,7 +28,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-500 - latin */ /* cormorant-garamond-500 - latin */
@font-face { @font-face {
@@ -36,7 +36,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-500italic - latin */ /* cormorant-garamond-500italic - latin */
@font-face { @font-face {
@@ -44,7 +44,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: italic; font-style: italic;
font-weight: 500; font-weight: 500;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-600 - latin */ /* cormorant-garamond-600 - latin */
@font-face { @font-face {
@@ -52,7 +52,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-600italic - latin */ /* cormorant-garamond-600italic - latin */
@font-face { @font-face {
@@ -60,7 +60,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: italic; font-style: italic;
font-weight: 600; font-weight: 600;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-700 - latin */ /* cormorant-garamond-700 - latin */
@font-face { @font-face {
@@ -68,7 +68,7 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
/* cormorant-garamond-700italic - latin */ /* cormorant-garamond-700italic - latin */
@font-face { @font-face {
@@ -76,5 +76,5 @@
font-family: 'Cormorant Garamond'; font-family: 'Cormorant Garamond';
font-style: italic; font-style: italic;
font-weight: 700; font-weight: 700;
src: url('../../fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ src: url('./assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
} }
+4
View File
@@ -0,0 +1,4 @@
@import "_fonts.css";
$header-font: "Cormorant Garamond", sans-serif;
$font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+13
View File
@@ -0,0 +1,13 @@
const CapitalIcon = () => (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14"
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
</svg>
);
export default CapitalIcon;
+12
View File
@@ -0,0 +1,12 @@
const DescriptionIcon = () => (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M3 10H16M3 14H21M3 18H16M3 6H21" stroke="#ffffff" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
</g>
</svg>
);
export default DescriptionIcon;
+13
View File
@@ -0,0 +1,13 @@
const PopulationIcon = () => (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M13 20V18C13 15.2386 10.7614 13 8 13C5.23858 13 3 15.2386 3 18V20H13ZM13 20H21V19C21 16.0545 18.7614 14 16 14C14.5867 14 13.3103 14.6255 12.4009 15.6311M11 7C11 8.65685 9.65685 10 8 10C6.34315 10 5 8.65685 5 7C5 5.34315 6.34315 4 8 4C9.65685 4 11 5.34315 11 7ZM18 9C18 10.1046 17.1046 11 16 11C14.8954 11 14 10.1046 14 9C14 7.89543 14.8954 7 16 7C17.1046 7 18 7.89543 18 9Z"
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
</svg>
);
export default PopulationIcon;
+13
View File
@@ -0,0 +1,13 @@
const RulerIcon = () => (
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path
d="M4 8L6 20H18L20 8M4 8L5.71624 9.37299C6.83218 10.2657 7.39014 10.7121 7.95256 10.7814C8.4453 10.8421 8.94299 10.7173 9.34885 10.4314C9.81211 10.1051 10.0936 9.4483 10.6565 8.13476L12 5M4 8C4.55228 8 5 7.55228 5 7C5 6.44772 4.55228 6 4 6C3.44772 6 3 6.44772 3 7C3 7.55228 3.44772 8 4 8ZM20 8L18.2838 9.373C17.1678 10.2657 16.6099 10.7121 16.0474 10.7814C15.5547 10.8421 15.057 10.7173 14.6511 10.4314C14.1879 10.1051 13.9064 9.4483 13.3435 8.13476L12 5M20 8C20.5523 8 21 7.55228 21 7C21 6.44772 20.5523 6 20 6C19.4477 6 19 6.44772 19 7C19 7.55228 19.4477 8 20 8ZM12 5C12.5523 5 13 4.55228 13 4C13 3.44772 12.5523 3 12 3C11.4477 3 11 3.44772 11 4C11 4.55228 11.4477 5 12 5ZM12 4H12.01M20 7H20.01M4 7H4.01"
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</g>
</svg>
);
export default RulerIcon;
+24
View File
@@ -0,0 +1,24 @@
.legend {
display: flex;
flex-direction: column;
padding: 0 15px;
flex-grow: 1;
h1 {
font-size: 3rem;
font-weight: 700;
width: fit-content;
margin-bottom: 12px;
margin-top: 20px;
@media (max-width: 768px) {
font-size: 1rem;
}
}
.border {
width: 100%;
height: 1px;
background-color: #d78453;
}
}
+13
View File
@@ -0,0 +1,13 @@
import "./Legend.scss";
const Legend = () => {
return (
<div className="legend">
<h1>Interactive Map of the Magic Continent</h1>
<div className="border"></div>
</div>
)
}
export default Legend;
+118
View File
@@ -0,0 +1,118 @@
import {MapLocation} from "../../types/MapLocation.ts";
import {MapRegion} from "../../types/MapRegion.ts";
import Capital from "./locations/Capital.tsx";
import City from "./locations/City.tsx";
import Poi from "./locations/Poi.tsx";
import {useState} from "react";
import MapLocationTooltip from "./tooltips/MapLocationTooltip.tsx";
import MapRegionTooltip from "./tooltips/MapRegionTooltip.tsx";
interface MapProps {
imageUrl: string;
regions?: MapRegion[];
capitals?: MapLocation[];
cities?: MapLocation[];
pois?: MapLocation[];
}
const Map: React.FC<MapProps> = ({imageUrl, regions = [], cities = [], pois = [], capitals = []}) => {
const [tooltip, setTooltip] = useState<{ visible: boolean; x: number; y: number; content: JSX.Element | null }>({
visible: false,
x: 0,
y: 0,
content: null,
});
const handleMouseEnterRegion = (event: React.MouseEvent<SVGPolygonElement>, region: MapRegion) => {
setTooltip({
visible: true,
x: event.clientX + 10,
y: event.clientY + 10,
content: <MapRegionTooltip region={region} />,
});
};
const handleMouseEnterLocation = (event: React.MouseEvent<SVGGElement>, location: MapLocation) => {
setTooltip({
visible: true,
x: event.clientX + 10,
y: event.clientY + 10,
content: <MapLocationTooltip location={location} />,
});
};
const handleMouseMove = (event: React.MouseEvent) => {
setTooltip(prev => ({
...prev,
x: event.clientX + 10,
y: event.clientY + 10,
}));
};
const handleMouseLeave = () => {
setTooltip({ visible: false, x: 0, y: 0, content: null });
};
return (
<>
<svg id="map" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2641 2035">
<image href={imageUrl} width="100%" />
{regions.map((region, index) => (
<polygon
key={index}
className="region"
points={region.points}
fill="transparent"
stroke="transparent"
strokeWidth={4}
onMouseEnter={(e) => handleMouseEnterRegion(e, region)}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
/>
))}
{capitals.map((location, index) => (
<Capital
key={index}
city={location}
onMouseEnter={(e) => handleMouseEnterLocation(e, location)}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
/>
))}
{cities.map((location, index) => (
<City
key={index}
city={location}
onMouseEnter={(e) => handleMouseEnterLocation(e, location)}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
/>
))}
{pois.map((location, index) => (
<Poi
key={index}
poi={location}
onMouseEnter={(e) => handleMouseEnterLocation(e, location)}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
/>
))}
</svg>
{tooltip.visible && (
<div
id={"tooltip"}
className={"tooltip"}
style={{
display: "flex",
left: tooltip.x,
top: tooltip.y,
}}
>
{tooltip.content}
</div>
)}
</>
);
}
export default Map;
+39
View File
@@ -0,0 +1,39 @@
import {MapLocation} from "../../../types/MapLocation.ts";
interface CapitalProps {
key: number;
city: MapLocation;
onMouseEnter: (event: React.MouseEvent<SVGGElement>, city: MapLocation) => void;
onMouseMove: (event: React.MouseEvent<SVGGElement>) => void;
onMouseLeave: () => void;
}
const Capital: React.FC<CapitalProps> = ({ key, city, onMouseEnter, onMouseMove, onMouseLeave }) => (
<g
key={key}
transform={`translate(${city.position.x}, ${city.position.y}) scale(2.5, 2.5)`}
fill="transparent"
className="location"
data-name={city.name ?? ""}
data-description={city.description ?? ""}
data-url={city.url ?? ""}
data-image-url={city.image?.url ?? ""}
data-image-credit={city.image?.credit ?? ""}
data-image-name={city.image?.name ?? ""}
onMouseEnter={(e) => onMouseEnter(e, city)}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
>
<rect x="0" y="0" width="24" height="24" fill="transparent" stroke="transparent" strokeWidth="4"/>
<path
d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14"
stroke="black" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round"
/>
<path
d="M4.5 14L3 15V21H7M7 21H10M7 21V13L9.5 11V6L12 3L14.5 6V11L17 13V21M10 21H14M10 21V17C10 15.8954 10.8954 15 12 15C13.1046 15 14 15.8954 14 17V21M14 21H17M17 21H21V15L19.5 14"
stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
/>
</g>
)
export default Capital;
+51
View File
@@ -0,0 +1,51 @@
import {MapLocation} from "../../../types/MapLocation.ts";
interface CityProps {
key: number;
city: MapLocation;
onMouseEnter: (event: React.MouseEvent<SVGGElement>, city: MapLocation) => void;
onMouseMove: (event: React.MouseEvent<SVGGElement>) => void;
onMouseLeave: () => void;
}
const City: React.FC<CityProps> = ({ key, city, onMouseEnter, onMouseMove, onMouseLeave }) => (
<g
key={key}
transform={`translate(${city.position.x}, ${city.position.y}) scale(2.5, 2.5)`}
fill="transparent"
className="location"
data-name={city.name ?? ""}
data-description={city.description ?? ""}
data-url={city.url ?? ""}
data-image-url={city.image?.url ?? ""}
data-image-credit={city.image?.credit ?? ""}
data-image-name={city.image?.name ?? ""}
onMouseEnter={(e) => onMouseEnter(e, city)}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
>
<rect x="0" y="0" width="24" height="24" fill="transparent" stroke="transparent" strokeWidth="4"/>
{/* Black border */}
<path
d="M15 3L3 19V21H21V19L9 3M12 15L16 21H8L12 15Z"
stroke="black"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
transform="scale(0.8, 0.8)"
/>
{/* White inner stroke */}
<path
d="M15 3L3 19V21H21V19L9 3M12 15L16 21H8L12 15Z"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
transform="scale(0.8, 0.8)"
/>
</g>
)
export default City;
+50
View File
@@ -0,0 +1,50 @@
import {MapLocation} from "../../../types/MapLocation.ts";
interface PoiProps {
key: number;
poi: MapLocation;
onMouseEnter: (event: React.MouseEvent<SVGGElement>, city: MapLocation) => void;
onMouseMove: (event: React.MouseEvent<SVGGElement>) => void;
onMouseLeave: () => void;
}
const City: React.FC<PoiProps> = ({ key, poi, onMouseMove, onMouseLeave, onMouseEnter }) => (
<g
key={key}
transform={`translate(${poi.position.x}, ${poi.position.y}) scale(2.5, 2.5)`}
fill="transparent"
className="location"
data-name={poi.name ?? ""}
data-description={poi.description ?? ""}
data-url={poi.url ?? ""}
data-image-url={poi.image?.url ?? ""}
data-image-credit={poi.image?.credit ?? ""}
data-image-name={poi.image?.name ?? ""}
onMouseEnter={(e) => onMouseEnter(e, poi)}
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
>
{/* Outer rectangle */}
<rect width="24" height="24" fill="transparent" stroke="transparent" strokeWidth="4" />
{/* Black border path */}
<path
d="M11.2691 4.41115C11.5006 3.89177 11.6164 3.63208 11.7776 3.55211C11.9176 3.48263 12.082 3.48263 12.222 3.55211C12.3832 3.63208 12.499 3.89177 12.7305 4.41115L14.5745 8.54808C14.643 8.70162 14.6772 8.77839 14.7302 8.83718C14.777 8.8892 14.8343 8.93081 14.8982 8.95929C14.9705 8.99149 15.0541 9.00031 15.2213 9.01795L19.7256 9.49336C20.2911 9.55304 20.5738 9.58288 20.6997 9.71147C20.809 9.82316 20.8598 9.97956 20.837 10.1342C20.8108 10.3122 20.5996 10.5025 20.1772 10.8832L16.8125 13.9154C16.6877 14.0279 16.6252 14.0842 16.5857 14.1527C16.5507 14.2134 16.5288 14.2807 16.5215 14.3503C16.5132 14.429 16.5306 14.5112 16.5655 14.6757L17.5053 19.1064C17.6233 19.6627 17.6823 19.9408 17.5989 20.1002C17.5264 20.2388 17.3934 20.3354 17.2393 20.3615C17.0619 20.3915 16.8156 20.2495 16.323 19.9654L12.3995 17.7024C12.2539 17.6184 12.1811 17.5765 12.1037 17.56C12.0352 17.5455 11.9644 17.5455 11.8959 17.56C11.8185 17.5765 11.7457 17.6184 11.6001 17.7024L7.67662 19.9654C7.18404 20.2495 6.93775 20.3915 6.76034 20.3615C6.60623 20.3354 6.47319 20.2388 6.40075 20.1002C6.31736 19.9408 6.37635 19.6627 6.49434 19.1064L7.4341 14.6757C7.46898 14.5112 7.48642 14.429 7.47814 14.3503C7.47081 14.2807 7.44894 14.2134 7.41394 14.1527C7.37439 14.0842 7.31195 14.0279 7.18708 13.9154L3.82246 10.8832C3.40005 10.5025 3.18884 10.3122 3.16258 10.1342C3.13978 9.97956 3.19059 9.82316 3.29993 9.71147C3.42581 9.58288 3.70856 9.55304 4.27406 9.49336L8.77835 9.01795C8.94553 9.00031 9.02911 8.99149 9.10139 8.95929C9.16534 8.93081 9.2226 8.8892 9.26946 8.83718C9.32241 8.77839 9.35663 8.70162 9.42508 8.54808L11.2691 4.41115Z"
stroke="black"
strokeWidth="4"
strokeLinecap="round"
strokeLinejoin="round"
/>
{/* White inner stroke */}
<path
d="M11.2691 4.41115C11.5006 3.89177 11.6164 3.63208 11.7776 3.55211C11.9176 3.48263 12.082 3.48263 12.222 3.55211C12.3832 3.63208 12.499 3.89177 12.7305 4.41115L14.5745 8.54808C14.643 8.70162 14.6772 8.77839 14.7302 8.83718C14.777 8.8892 14.8343 8.93081 14.8982 8.95929C14.9705 8.99149 15.0541 9.00031 15.2213 9.01795L19.7256 9.49336C20.2911 9.55304 20.5738 9.58288 20.6997 9.71147C20.809 9.82316 20.8598 9.97956 20.837 10.1342C20.8108 10.3122 20.5996 10.5025 20.1772 10.8832L16.8125 13.9154C16.6877 14.0279 16.6252 14.0842 16.5857 14.1527C16.5507 14.2134 16.5288 14.2807 16.5215 14.3503C16.5132 14.429 16.5306 14.5112 16.5655 14.6757L17.5053 19.1064C17.6233 19.6627 17.6823 19.9408 17.5989 20.1002C17.5264 20.2388 17.3934 20.3354 17.2393 20.3615C17.0619 20.3915 16.8156 20.2495 16.323 19.9654L12.3995 17.7024C12.2539 17.6184 12.1811 17.5765 12.1037 17.56C12.0352 17.5455 11.9644 17.5455 11.8959 17.56C11.8185 17.5765 11.7457 17.6184 11.6001 17.7024L7.67662 19.9654C7.18404 20.2495 6.93775 20.3915 6.76034 20.3615C6.60623 20.3354 6.47319 20.2388 6.40075 20.1002C6.31736 19.9408 6.37635 19.6627 6.49434 19.1064L7.4341 14.6757C7.46898 14.5112 7.48642 14.429 7.47814 14.3503C7.47081 14.2807 7.44894 14.2134 7.41394 14.1527C7.37439 14.0842 7.31195 14.0279 7.18708 13.9154L3.82246 10.8832C3.40005 10.5025 3.18884 10.3122 3.16258 10.1342C3.13978 9.97956 3.19059 9.82316 3.29993 9.71147C3.42581 9.58288 3.70856 9.55304 4.27406 9.49336L8.77835 9.01795C8.94553 9.00031 9.02911 8.99149 9.10139 8.95929C9.16534 8.93081 9.2226 8.8892 9.26946 8.83718C9.32241 8.77839 9.35663 8.70162 9.42508 8.54808L11.2691 4.41115Z"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
)
export default City;
@@ -0,0 +1,38 @@
import {MapLocation} from "../../../types/MapLocation.ts";
interface MapLocationTooltipProps {
location: MapLocation;
}
const MapLocationTooltip: React.FC<MapLocationTooltipProps> = ({ location }) => {
return (
<>
<h3>{location.name}</h3>
<div className="border"></div>
{location.description && (
<span dangerouslySetInnerHTML={{__html: location.description}}/>
)}
{location.image?.url && (
<img
className={"locationimg"}
src={location.image.url}
alt={location.image.name ?? location.name}
title={location.image.credit ?? ""}
/>
)}
{location.url && (
<a
className={"more"}
href={location.url}
target={"_blank"}
rel={"noreferrer noopener"}
>
<img src="img/icons/book.svg" alt="wiki icon"/>
Wiki
</a>
)}
</>
)
};
export default MapLocationTooltip;
@@ -0,0 +1,55 @@
import {MapRegion} from "../../../types/MapRegion.ts";
import CapitalIcon from "../../icons/CapitalIcon.tsx";
import PopulationIcon from "../../icons/PopulationIcon.tsx";
import RulerIcon from "../../icons/RulerIcon.tsx";
import DescriptionIcon from "../../icons/DescriptionIcon.tsx";
interface MapLocationTooltipProps {
region: MapRegion;
}
const MapLocationTooltip: React.FC<MapLocationTooltipProps> = ({ region }) => {
return (
<>
<h3>{region.name}</h3>
<div className="border"></div>
{region.capital && (
<div className="detailbox">
<CapitalIcon />
<span dangerouslySetInnerHTML={{__html: region.capital}}/>
</div>
)}
{region.population && (
<div className="detailbox">
<PopulationIcon />
<span dangerouslySetInnerHTML={{__html: region.population}}/>
</div>
)}
{region.ruler && (
<div className="detailbox">
<RulerIcon />
<span dangerouslySetInnerHTML={{__html: region.ruler}}/>
</div>
)}
{region.description && (
<div className="detailbox">
<DescriptionIcon />
<span dangerouslySetInnerHTML={{__html: region.description}}/>
</div>
)}
{region.url && (
<a
className={"more"}
href={region.url}
target={"_blank"}
rel={"noreferrer noopener"}
>
<img src="img/icons/book.svg" alt="wiki icon"/>
Wiki
</a>
)}
</>
)
};
export default MapLocationTooltip;
@@ -1,23 +1,6 @@
/** import {MapLocation} from "../types/MapLocation.ts";
* @typedef {Object} CapitalData
* @property {string} name
* @property {string?} description
* @property {CapitalImage?} image
* @property {string?} url
* @property {{x:string,y:string}} position
*/
/** const capitals: MapLocation[] = [
* @typedef {Object} CapitalImage
* @property {string} url
* @property {string} name
* @property {string} credit
*/
/**
* @type {[CapitalData]}
*/
export const capitals = [
{ {
name: "Lune", name: "Lune",
description: "The capital of the Holy Empire Lubelius, home of God Luminous.", description: "The capital of the Holy Empire Lubelius, home of God Luminous.",
@@ -149,4 +132,6 @@ export const capitals = [
url: "https://tensura.fandom.com/wiki/Golden_City_of_El_Dorado", url: "https://tensura.fandom.com/wiki/Golden_City_of_El_Dorado",
position: { x: "800", y: "1565" } position: { x: "800", y: "1565" }
}, },
] ];
export default capitals;
+4 -19
View File
@@ -1,23 +1,6 @@
/** import {MapLocation} from "../types/MapLocation.ts";
* @typedef {Object} CityData
* @property {string} name
* @property {string?} description
* @property {CityImage?} image
* @property {string?} url
* @property {{x:string,y:string}} position
*/
/** const cities: MapLocation[] = [
* @typedef {Object} CityImage
* @property {string} url
* @property {string} name
* @property {string} credit
*/
/**
* @type {[CapitalData]}
*/
export const cities = [
{ {
name: "Tengu Village", name: "Tengu Village",
description: "The village of the Tengu tribe, located in the Khusha Mountains.", description: "The village of the Tengu tribe, located in the Khusha Mountains.",
@@ -74,3 +57,5 @@ export const cities = [
position: { x: "1224", y: "1010" } position: { x: "1224", y: "1010" }
}, },
]; ];
export default cities;
@@ -1,18 +1,6 @@
/** import {MapRegion} from "../types/MapRegion.ts";
* @typedef {Object} NationData
* @property {string} name
* @property {string} capital
* @property {string} description
* @property {string} ruler
* @property {string} population
* @property {string?} url
* @property {string} points
*/
/** const nations: MapRegion[] = [
* @type {[NationData]}
*/
export const nations = [
{ {
name: "Kingdom of Englassia", name: "Kingdom of Englassia",
url: "https://tensura.fandom.com/wiki/Kingdom_of_Englassia", url: "https://tensura.fandom.com/wiki/Kingdom_of_Englassia",
@@ -185,3 +173,5 @@ export const nations = [
points: "1131, 1345, 1142, 1339, 1156, 1337, 1173, 1336, 1181, 1342, 1187, 1345, 1190, 1349, 1193, 1360, 1182, 1363, 1173, 1367, 1167, 1375, 1160, 1375, 1155, 1368, 1146, 1358, 1139, 1352" points: "1131, 1345, 1142, 1339, 1156, 1337, 1173, 1336, 1181, 1342, 1187, 1345, 1190, 1349, 1193, 1360, 1182, 1363, 1173, 1367, 1167, 1375, 1160, 1375, 1155, 1368, 1146, 1358, 1139, 1352"
}, },
] ]
export default nations;
+5 -20
View File
@@ -1,23 +1,6 @@
/** import {MapLocation} from "../types/MapLocation.ts";
* @typedef {Object} POIData
* @property {string} name
* @property {string} description
* @property {POIImage?} image
* @property {string?} url
* @property {{x:string,y:string}} position
*/
/** const pois: MapLocation[] = [
* @typedef {Object} POIImage
* @property {string} url
* @property {string} name
* @property {string} credit
*/
/**
* @type {[POIData]}
*/
export const pois = [
{ {
name: "Sealed Cave", name: "Sealed Cave",
description: "The cave where Veldora was sealed and where Rimuru was born.", description: "The cave where Veldora was sealed and where Rimuru was born.",
@@ -100,4 +83,6 @@ export const pois = [
description: "The uninhabitable region laid to waste during the battle between Guy and Milim 2,000 years ago.", description: "The uninhabitable region laid to waste during the battle between Guy and Milim 2,000 years ago.",
position: { x: "509", y: "940" } position: { x: "509", y: "940" }
}, },
] ];
export default pois;
+22 -31
View File
@@ -1,9 +1,13 @@
@import "fonts/cormant_garamont.css"; @import "variables";
//@import "fonts/crimson_pro.css";
:root { #root {
--header-font: "Cormorant Garamond", sans-serif; padding: 0;
--body-font: "Crimson Pro", sans-serif; margin: 0;
width: 100%;
height: 100%;
display: flex;
} }
body { body {
@@ -22,7 +26,7 @@ body {
color: #d78453; color: #d78453;
font-size: 16px; font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";; font-family: $font;
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
@@ -75,31 +79,6 @@ a {
fill: rgb(252, 161, 113, .3); fill: rgb(252, 161, 113, .3);
} }
.legend {
display: flex;
flex-direction: column;
padding: 0 15px;
flex-grow: 1;
h1 {
font-size: 3rem;
font-weight: 700;
width: fit-content;
margin-bottom: 12px;
margin-top: 20px;
@media (max-width: 768px) {
font-size: 1rem;
}
}
.border {
width: 100%;
height: 1px;
background-color: #d78453;
}
}
@media (max-width: 1200px) { @media (max-width: 1200px) {
body { body {
flex-direction: column; flex-direction: column;
@@ -157,6 +136,18 @@ a {
border-radius: 5px; border-radius: 5px;
} }
a.more {
display: flex;
align-items: center;
gap: 7px;
img {
--hw: 23px;
height: var(--hw);
width: var(--hw);
}
}
.detailbox { .detailbox {
display: flex; display: flex;
//align-items: center; //align-items: center;
+10
View File
@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.scss'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
+23
View File
@@ -0,0 +1,23 @@
import Legend from "../components/layout/Legend.tsx";
import Map from "../components/map/Map.tsx";
import nations from "../data/nations.ts";
import cities from "../data/cities.ts";
import capitals from "../data/capitals.ts";
import pois from "../data/pois.ts";
const Main = () => {
return (
<>
<Map
imageUrl={"/img/map.webp"}
regions={nations}
cities={cities}
capitals={capitals}
pois={pois}
/>
<Legend />
</>
);
}
export default Main;

Some files were not shown because too many files have changed in this diff Show More