diff --git a/.gitignore b/.gitignore
index ab477e2..a547bf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,24 @@
-htmlmap.html
\ No newline at end of file
+# 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?
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index b58b603..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml
index c70980f..fb0d65a 100644
--- a/.idea/watcherTasks.xml
+++ b/.idea/watcherTasks.xml
@@ -1,25 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 0000000..de964e2
Binary files /dev/null and b/bun.lockb differ
diff --git a/css/.gitignore b/css/.gitignore
deleted file mode 100644
index 5229096..0000000
--- a/css/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Ignore all CSS files
-*.css
-
-# Ignore all CSS map files
-*.css.map
\ No newline at end of file
diff --git a/css/fonts/crimson_pro.css b/css/fonts/crimson_pro.css
deleted file mode 100644
index 8d9f68b..0000000
--- a/css/fonts/crimson_pro.css
+++ /dev/null
@@ -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+ */
-}
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..092408a
--- /dev/null
+++ b/eslint.config.js
@@ -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 },
+ ],
+ },
+ },
+)
diff --git a/index.html b/index.html
index 5959289..af7f17b 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,9 @@
-
+
-
-
+
+
+
Interactive Tensei Shitara Slime Datta Ken Map
@@ -29,21 +30,9 @@
-
-
-
-
-
-
-
-
-
Interactive Map of the Magic Continent
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/js/Map.js b/js/Map.js
deleted file mode 100644
index ee802c3..0000000
--- a/js/Map.js
+++ /dev/null
@@ -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 += ``;
-
- 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;
- }
-}
\ No newline at end of file
diff --git a/js/SlimeMap.js b/js/SlimeMap.js
deleted file mode 100644
index b15023d..0000000
--- a/js/SlimeMap.js
+++ /dev/null
@@ -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 = `
-
-
-
-
-
-
- `;
- this.addSVGElement(svgString);
- }
- }
-
- addCities() {
- for (let city of this.cities) {
- const svgString = `
-
-
-
-
-
-
- `;
- this.addSVGElement(svgString);
- }
- }
-
- addPOIs() {
- for (let poi of this.pois) {
- const svgString = `
-
-
-
-
-
-
- `;
- this.addSVGElement(svgString);
- }
- }
-}
\ No newline at end of file
diff --git a/js/locations/index.js b/js/locations/index.js
deleted file mode 100644
index 99ae579..0000000
--- a/js/locations/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from "./pois.js";
-export * from "./nations.js";
-export * from "./capitals.js";
-export * from "./cities.js";
\ No newline at end of file
diff --git a/js/mapBuilder.js b/js/mapBuilder.js
deleted file mode 100644
index ba0eba9..0000000
--- a/js/mapBuilder.js
+++ /dev/null
@@ -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);
\ No newline at end of file
diff --git a/js/tooltip.js b/js/tooltip.js
deleted file mode 100644
index 35708ba..0000000
--- a/js/tooltip.js
+++ /dev/null
@@ -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 ? `${regionName}
` : `${regionName}
`;
- let data = `${regionName}
`;
-
- data += ``;
-
- if (regionCapital) data += `
-
- `;
- if (regionPopulation) data += `
-
-
-
${regionPopulation}
-
- `;
- if (regionRuler) data += `
-
- `;
- if (regionDescription) data += `
-
-
-
${regionDescription}
-
- `;
-
- if (url) data += `
Wiki`;
-
- 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 ? `${locationName}
` : `${locationName}
`;
- let locationString = `${locationName}
`;
-
- if (locationDescription || imageUrl) locationString += ``;
- if (locationDescription) locationString += `${locationDescription}`;
- if (imageUrl) locationString += `
`;
- if (url) locationString += `
Wiki`;
-
- return locationString;
-}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8d97e04
--- /dev/null
+++ b/package.json
@@ -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"
+ }
+}
diff --git a/img/favicon/apple-touch-icon.png b/public/img/favicon/apple-touch-icon.png
similarity index 100%
rename from img/favicon/apple-touch-icon.png
rename to public/img/favicon/apple-touch-icon.png
diff --git a/img/favicon/favicon-48x48.png b/public/img/favicon/favicon-48x48.png
similarity index 100%
rename from img/favicon/favicon-48x48.png
rename to public/img/favicon/favicon-48x48.png
diff --git a/img/favicon/favicon.ico b/public/img/favicon/favicon.ico
similarity index 100%
rename from img/favicon/favicon.ico
rename to public/img/favicon/favicon.ico
diff --git a/img/favicon/favicon.svg b/public/img/favicon/favicon.svg
similarity index 100%
rename from img/favicon/favicon.svg
rename to public/img/favicon/favicon.svg
diff --git a/img/favicon/site.webmanifest b/public/img/favicon/site.webmanifest
similarity index 100%
rename from img/favicon/site.webmanifest
rename to public/img/favicon/site.webmanifest
diff --git a/img/favicon/web-app-manifest-192x192.png b/public/img/favicon/web-app-manifest-192x192.png
similarity index 100%
rename from img/favicon/web-app-manifest-192x192.png
rename to public/img/favicon/web-app-manifest-192x192.png
diff --git a/img/favicon/web-app-manifest-512x512.png b/public/img/favicon/web-app-manifest-512x512.png
similarity index 100%
rename from img/favicon/web-app-manifest-512x512.png
rename to public/img/favicon/web-app-manifest-512x512.png
diff --git a/img/icons/book.svg b/public/img/icons/book.svg
similarity index 100%
rename from img/icons/book.svg
rename to public/img/icons/book.svg
diff --git a/img/icons/campground.svg b/public/img/icons/campground.svg
similarity index 100%
rename from img/icons/campground.svg
rename to public/img/icons/campground.svg
diff --git a/img/icons/house.svg b/public/img/icons/house.svg
similarity index 100%
rename from img/icons/house.svg
rename to public/img/icons/house.svg
diff --git a/img/icons/star.svg b/public/img/icons/star.svg
similarity index 100%
rename from img/icons/star.svg
rename to public/img/icons/star.svg
diff --git a/img/icons/village.svg b/public/img/icons/village.svg
similarity index 100%
rename from img/icons/village.svg
rename to public/img/icons/village.svg
diff --git a/img/locations/amrita.webp b/public/img/locations/amrita.webp
similarity index 100%
rename from img/locations/amrita.webp
rename to public/img/locations/amrita.webp
diff --git a/img/locations/charybdis_cave.webp b/public/img/locations/charybdis_cave.webp
similarity index 100%
rename from img/locations/charybdis_cave.webp
rename to public/img/locations/charybdis_cave.webp
diff --git a/img/locations/city_of_the_forgotten_dragon.webp b/public/img/locations/city_of_the_forgotten_dragon.webp
similarity index 100%
rename from img/locations/city_of_the_forgotten_dragon.webp
rename to public/img/locations/city_of_the_forgotten_dragon.webp
diff --git a/img/locations/dwargon_gate.webp b/public/img/locations/dwargon_gate.webp
similarity index 100%
rename from img/locations/dwargon_gate.webp
rename to public/img/locations/dwargon_gate.webp
diff --git a/img/locations/el_dorado.webp b/public/img/locations/el_dorado.webp
similarity index 100%
rename from img/locations/el_dorado.webp
rename to public/img/locations/el_dorado.webp
diff --git a/img/locations/elmine.webp b/public/img/locations/elmine.webp
similarity index 100%
rename from img/locations/elmine.webp
rename to public/img/locations/elmine.webp
diff --git a/img/locations/guratol_county.webp b/public/img/locations/guratol_county.webp
similarity index 100%
rename from img/locations/guratol_county.webp
rename to public/img/locations/guratol_county.webp
diff --git a/img/locations/ice_palace.webp b/public/img/locations/ice_palace.webp
similarity index 100%
rename from img/locations/ice_palace.webp
rename to public/img/locations/ice_palace.webp
diff --git a/img/locations/jia.webp b/public/img/locations/jia.webp
similarity index 100%
rename from img/locations/jia.webp
rename to public/img/locations/jia.webp
diff --git a/img/locations/khusha_mountains.webp b/public/img/locations/khusha_mountains.webp
similarity index 100%
rename from img/locations/khusha_mountains.webp
rename to public/img/locations/khusha_mountains.webp
diff --git a/img/locations/lake_siss.webp b/public/img/locations/lake_siss.webp
similarity index 100%
rename from img/locations/lake_siss.webp
rename to public/img/locations/lake_siss.webp
diff --git a/img/locations/laura.webp b/public/img/locations/laura.webp
similarity index 100%
rename from img/locations/laura.webp
rename to public/img/locations/laura.webp
diff --git a/img/locations/londo.webp b/public/img/locations/londo.webp
similarity index 100%
rename from img/locations/londo.webp
rename to public/img/locations/londo.webp
diff --git a/img/locations/lune.webp b/public/img/locations/lune.webp
similarity index 100%
rename from img/locations/lune.webp
rename to public/img/locations/lune.webp
diff --git a/img/locations/marris.webp b/public/img/locations/marris.webp
similarity index 100%
rename from img/locations/marris.webp
rename to public/img/locations/marris.webp
diff --git a/img/locations/migam_domain.webp b/public/img/locations/migam_domain.webp
similarity index 100%
rename from img/locations/migam_domain.webp
rename to public/img/locations/migam_domain.webp
diff --git a/img/locations/ogre_village.webp b/public/img/locations/ogre_village.webp
similarity index 100%
rename from img/locations/ogre_village.webp
rename to public/img/locations/ogre_village.webp
diff --git a/img/locations/rimuru_city.webp b/public/img/locations/rimuru_city.webp
similarity index 100%
rename from img/locations/rimuru_city.webp
rename to public/img/locations/rimuru_city.webp
diff --git a/img/locations/sealed_cave.webp b/public/img/locations/sealed_cave.webp
similarity index 100%
rename from img/locations/sealed_cave.webp
rename to public/img/locations/sealed_cave.webp
diff --git a/img/locations/tengu_village.webp b/public/img/locations/tengu_village.webp
similarity index 100%
rename from img/locations/tengu_village.webp
rename to public/img/locations/tengu_village.webp
diff --git a/img/map.webp b/public/img/map.webp
similarity index 100%
rename from img/map.webp
rename to public/img/map.webp
diff --git a/img/ogImage.png b/public/img/ogImage.png
similarity index 100%
rename from img/ogImage.png
rename to public/img/ogImage.png
diff --git a/img/slime.svg b/public/img/slime.svg
similarity index 100%
rename from img/slime.svg
rename to public/img/slime.svg
diff --git a/img/twitterImage.png b/public/img/twitterImage.png
similarity index 100%
rename from img/twitterImage.png
rename to public/img/twitterImage.png
diff --git a/src/App.scss b/src/App.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/App.tsx b/src/App.tsx
new file mode 100644
index 0000000..24b3467
--- /dev/null
+++ b/src/App.tsx
@@ -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 (
+
+
+ } />
+
+
+ )
+}
+
+export default App
diff --git a/css/fonts/cormant_garamont.css b/src/_fonts.css
similarity index 63%
rename from css/fonts/cormant_garamont.css
rename to src/_fonts.css
index aa457b9..9e90bce 100644
--- a/css/fonts/cormant_garamont.css
+++ b/src/_fonts.css
@@ -4,7 +4,7 @@
font-family: 'Cormorant Garamond';
font-style: normal;
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 */
@font-face {
@@ -12,7 +12,7 @@
font-family: 'Cormorant Garamond';
font-style: italic;
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 */
@font-face {
@@ -20,7 +20,7 @@
font-family: 'Cormorant Garamond';
font-style: normal;
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 */
@font-face {
@@ -28,7 +28,7 @@
font-family: 'Cormorant Garamond';
font-style: italic;
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 */
@font-face {
@@ -36,7 +36,7 @@
font-family: 'Cormorant Garamond';
font-style: normal;
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 */
@font-face {
@@ -44,7 +44,7 @@
font-family: 'Cormorant Garamond';
font-style: italic;
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 */
@font-face {
@@ -52,7 +52,7 @@
font-family: 'Cormorant Garamond';
font-style: normal;
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 */
@font-face {
@@ -60,7 +60,7 @@
font-family: 'Cormorant Garamond';
font-style: italic;
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 */
@font-face {
@@ -68,7 +68,7 @@
font-family: 'Cormorant Garamond';
font-style: normal;
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 */
@font-face {
@@ -76,5 +76,5 @@
font-family: 'Cormorant Garamond';
font-style: italic;
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+ */
}
\ No newline at end of file
diff --git a/src/_variables.scss b/src/_variables.scss
new file mode 100644
index 0000000..17d2616
--- /dev/null
+++ b/src/_variables.scss
@@ -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";
\ No newline at end of file
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-300italic.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-500italic.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-600italic.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-700italic.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-italic.woff2
diff --git a/fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2 b/src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2
similarity index 100%
rename from fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2
rename to src/assets/fonts/cormant_garamond/cormorant-garamond-v16-latin-regular.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-200.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-200.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-200.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-200.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-200italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-200italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-200italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-200italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-300.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-300.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-300.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-300.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-300italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-300italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-300italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-300italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-500.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-500.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-500.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-500.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-500italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-500italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-500italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-500italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-600.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-600.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-600.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-600.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-600italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-600italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-600italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-600italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-700.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-700.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-700.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-700.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-700italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-700italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-700italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-700italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-800.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-800.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-800.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-800.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-800italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-800italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-800italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-800italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-900.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-900.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-900.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-900.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-900italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-900italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-900italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-900italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-italic.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-italic.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-italic.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-italic.woff2
diff --git a/fonts/crimson_pro/crimson-pro-v24-latin-regular.woff2 b/src/assets/fonts/crimson_pro/crimson-pro-v24-latin-regular.woff2
similarity index 100%
rename from fonts/crimson_pro/crimson-pro-v24-latin-regular.woff2
rename to src/assets/fonts/crimson_pro/crimson-pro-v24-latin-regular.woff2
diff --git a/src/components/icons/CapitalIcon.tsx b/src/components/icons/CapitalIcon.tsx
new file mode 100644
index 0000000..9e7b42c
--- /dev/null
+++ b/src/components/icons/CapitalIcon.tsx
@@ -0,0 +1,13 @@
+const CapitalIcon = () => (
+
+);
+
+export default CapitalIcon;
\ No newline at end of file
diff --git a/src/components/icons/DescriptionIcon.tsx b/src/components/icons/DescriptionIcon.tsx
new file mode 100644
index 0000000..ea164a3
--- /dev/null
+++ b/src/components/icons/DescriptionIcon.tsx
@@ -0,0 +1,12 @@
+const DescriptionIcon = () => (
+
+);
+
+export default DescriptionIcon;
\ No newline at end of file
diff --git a/src/components/icons/PopulationIcon.tsx b/src/components/icons/PopulationIcon.tsx
new file mode 100644
index 0000000..3228514
--- /dev/null
+++ b/src/components/icons/PopulationIcon.tsx
@@ -0,0 +1,13 @@
+const PopulationIcon = () => (
+
+);
+
+export default PopulationIcon;
\ No newline at end of file
diff --git a/src/components/icons/RulerIcon.tsx b/src/components/icons/RulerIcon.tsx
new file mode 100644
index 0000000..1c33ce9
--- /dev/null
+++ b/src/components/icons/RulerIcon.tsx
@@ -0,0 +1,13 @@
+const RulerIcon = () => (
+
+);
+
+export default RulerIcon;
\ No newline at end of file
diff --git a/src/components/layout/Legend.scss b/src/components/layout/Legend.scss
new file mode 100644
index 0000000..1407d21
--- /dev/null
+++ b/src/components/layout/Legend.scss
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/components/layout/Legend.tsx b/src/components/layout/Legend.tsx
new file mode 100644
index 0000000..777b0de
--- /dev/null
+++ b/src/components/layout/Legend.tsx
@@ -0,0 +1,13 @@
+import "./Legend.scss";
+
+const Legend = () => {
+
+ return (
+
+
Interactive Map of the Magic Continent
+
+
+ )
+}
+
+export default Legend;
\ No newline at end of file
diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx
new file mode 100644
index 0000000..f198f8c
--- /dev/null
+++ b/src/components/map/Map.tsx
@@ -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 = ({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, region: MapRegion) => {
+ setTooltip({
+ visible: true,
+ x: event.clientX + 10,
+ y: event.clientY + 10,
+ content: ,
+ });
+ };
+
+ const handleMouseEnterLocation = (event: React.MouseEvent, location: MapLocation) => {
+ setTooltip({
+ visible: true,
+ x: event.clientX + 10,
+ y: event.clientY + 10,
+ content: ,
+ });
+ };
+
+ 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 (
+ <>
+
+ {tooltip.visible && (
+
+ {tooltip.content}
+
+ )}
+ >
+ );
+}
+
+export default Map;
\ No newline at end of file
diff --git a/src/components/map/locations/Capital.tsx b/src/components/map/locations/Capital.tsx
new file mode 100644
index 0000000..552da01
--- /dev/null
+++ b/src/components/map/locations/Capital.tsx
@@ -0,0 +1,39 @@
+import {MapLocation} from "../../../types/MapLocation.ts";
+
+interface CapitalProps {
+ key: number;
+ city: MapLocation;
+ onMouseEnter: (event: React.MouseEvent, city: MapLocation) => void;
+ onMouseMove: (event: React.MouseEvent) => void;
+ onMouseLeave: () => void;
+}
+
+const Capital: React.FC = ({ key, city, onMouseEnter, onMouseMove, onMouseLeave }) => (
+ onMouseEnter(e, city)}
+ onMouseMove={onMouseMove}
+ onMouseLeave={onMouseLeave}
+ >
+
+
+
+
+)
+
+export default Capital;
\ No newline at end of file
diff --git a/src/components/map/locations/City.tsx b/src/components/map/locations/City.tsx
new file mode 100644
index 0000000..a1535a3
--- /dev/null
+++ b/src/components/map/locations/City.tsx
@@ -0,0 +1,51 @@
+import {MapLocation} from "../../../types/MapLocation.ts";
+
+interface CityProps {
+ key: number;
+ city: MapLocation;
+ onMouseEnter: (event: React.MouseEvent, city: MapLocation) => void;
+ onMouseMove: (event: React.MouseEvent) => void;
+ onMouseLeave: () => void;
+}
+
+const City: React.FC = ({ key, city, onMouseEnter, onMouseMove, onMouseLeave }) => (
+ onMouseEnter(e, city)}
+ onMouseMove={onMouseMove}
+ onMouseLeave={onMouseLeave}
+ >
+
+
+ {/* Black border */}
+
+
+ {/* White inner stroke */}
+
+
+)
+
+export default City;
\ No newline at end of file
diff --git a/src/components/map/locations/Poi.tsx b/src/components/map/locations/Poi.tsx
new file mode 100644
index 0000000..d4409c0
--- /dev/null
+++ b/src/components/map/locations/Poi.tsx
@@ -0,0 +1,50 @@
+import {MapLocation} from "../../../types/MapLocation.ts";
+
+interface PoiProps {
+ key: number;
+ poi: MapLocation;
+ onMouseEnter: (event: React.MouseEvent, city: MapLocation) => void;
+ onMouseMove: (event: React.MouseEvent) => void;
+ onMouseLeave: () => void;
+}
+
+const City: React.FC = ({ key, poi, onMouseMove, onMouseLeave, onMouseEnter }) => (
+ onMouseEnter(e, poi)}
+ onMouseMove={onMouseMove}
+ onMouseLeave={onMouseLeave}
+ >
+ {/* Outer rectangle */}
+
+
+ {/* Black border path */}
+
+
+ {/* White inner stroke */}
+
+
+)
+
+export default City;
\ No newline at end of file
diff --git a/src/components/map/tooltips/MapLocationTooltip.tsx b/src/components/map/tooltips/MapLocationTooltip.tsx
new file mode 100644
index 0000000..82cc465
--- /dev/null
+++ b/src/components/map/tooltips/MapLocationTooltip.tsx
@@ -0,0 +1,38 @@
+import {MapLocation} from "../../../types/MapLocation.ts";
+
+interface MapLocationTooltipProps {
+ location: MapLocation;
+}
+
+const MapLocationTooltip: React.FC = ({ location }) => {
+ return (
+ <>
+ {location.name}
+
+ {location.description && (
+
+ )}
+ {location.image?.url && (
+
+ )}
+ {location.url && (
+
+
+ Wiki
+
+ )}
+ >
+ )
+};
+
+export default MapLocationTooltip;
\ No newline at end of file
diff --git a/src/components/map/tooltips/MapRegionTooltip.tsx b/src/components/map/tooltips/MapRegionTooltip.tsx
new file mode 100644
index 0000000..4d7dd66
--- /dev/null
+++ b/src/components/map/tooltips/MapRegionTooltip.tsx
@@ -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 = ({ region }) => {
+ return (
+ <>
+ {region.name}
+
+ {region.capital && (
+
+
+
+
+ )}
+ {region.population && (
+
+ )}
+ {region.ruler && (
+
+
+
+
+ )}
+ {region.description && (
+
+
+
+
+ )}
+ {region.url && (
+
+
+ Wiki
+
+ )}
+ >
+ )
+};
+
+export default MapLocationTooltip;
\ No newline at end of file
diff --git a/js/locations/capitals.js b/src/data/capitals.ts
similarity index 93%
rename from js/locations/capitals.js
rename to src/data/capitals.ts
index 39d7b7b..05f49c1 100644
--- a/js/locations/capitals.js
+++ b/src/data/capitals.ts
@@ -1,23 +1,6 @@
-/**
- * @typedef {Object} CapitalData
- * @property {string} name
- * @property {string?} description
- * @property {CapitalImage?} image
- * @property {string?} url
- * @property {{x:string,y:string}} position
- */
+import {MapLocation} from "../types/MapLocation.ts";
-/**
- * @typedef {Object} CapitalImage
- * @property {string} url
- * @property {string} name
- * @property {string} credit
- */
-
-/**
- * @type {[CapitalData]}
- */
-export const capitals = [
+const capitals: MapLocation[] = [
{
name: "Lune",
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",
position: { x: "800", y: "1565" }
},
-]
\ No newline at end of file
+];
+
+export default capitals;
\ No newline at end of file
diff --git a/js/locations/cities.js b/src/data/cities.ts
similarity index 86%
rename from js/locations/cities.js
rename to src/data/cities.ts
index db3a9c0..2adc0d8 100644
--- a/js/locations/cities.js
+++ b/src/data/cities.ts
@@ -1,23 +1,6 @@
-/**
- * @typedef {Object} CityData
- * @property {string} name
- * @property {string?} description
- * @property {CityImage?} image
- * @property {string?} url
- * @property {{x:string,y:string}} position
- */
+import {MapLocation} from "../types/MapLocation.ts";
-/**
- * @typedef {Object} CityImage
- * @property {string} url
- * @property {string} name
- * @property {string} credit
- */
-
-/**
- * @type {[CapitalData]}
- */
-export const cities = [
+const cities: MapLocation[] = [
{
name: "Tengu Village",
description: "The village of the Tengu tribe, located in the Khusha Mountains.",
@@ -73,4 +56,6 @@ export const cities = [
},
position: { x: "1224", y: "1010" }
},
-];
\ No newline at end of file
+];
+
+export default cities;
\ No newline at end of file
diff --git a/js/locations/nations.js b/src/data/nations.ts
similarity index 99%
rename from js/locations/nations.js
rename to src/data/nations.ts
index 5092e1c..bcf2807 100644
--- a/js/locations/nations.js
+++ b/src/data/nations.ts
@@ -1,18 +1,6 @@
-/**
- * @typedef {Object} NationData
- * @property {string} name
- * @property {string} capital
- * @property {string} description
- * @property {string} ruler
- * @property {string} population
- * @property {string?} url
- * @property {string} points
- */
+import {MapRegion} from "../types/MapRegion.ts";
-/**
- * @type {[NationData]}
- */
-export const nations = [
+const nations: MapRegion[] = [
{
name: "Kingdom of Englassia",
url: "https://tensura.fandom.com/wiki/Kingdom_of_Englassia",
@@ -184,4 +172,6 @@ export const nations = [
description: "The Kingdom of Malukshure is a small coastal nation known for its high concentration of mages and close ties to the Magic Tower. With a rich magical history and diplomatic relations with Tempest, its economy thrives on the export of small ocean fish and magical advancements, while the capital, Sainte-Malukshure, is protected by a powerful barrier maintained by the Trinity Wisemen.",
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"
},
-]
\ No newline at end of file
+]
+
+export default nations;
\ No newline at end of file
diff --git a/js/locations/pois.js b/src/data/pois.ts
similarity index 90%
rename from js/locations/pois.js
rename to src/data/pois.ts
index fdab84f..8adb484 100644
--- a/js/locations/pois.js
+++ b/src/data/pois.ts
@@ -1,23 +1,6 @@
-/**
- * @typedef {Object} POIData
- * @property {string} name
- * @property {string} description
- * @property {POIImage?} image
- * @property {string?} url
- * @property {{x:string,y:string}} position
- */
+import {MapLocation} from "../types/MapLocation.ts";
-/**
- * @typedef {Object} POIImage
- * @property {string} url
- * @property {string} name
- * @property {string} credit
- */
-
-/**
- * @type {[POIData]}
- */
-export const pois = [
+const pois: MapLocation[] = [
{
name: "Sealed Cave",
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.",
position: { x: "509", y: "940" }
},
-]
\ No newline at end of file
+];
+
+export default pois;
\ No newline at end of file
diff --git a/css/styles.scss b/src/index.scss
similarity index 77%
rename from css/styles.scss
rename to src/index.scss
index 5d44f31..dc28da8 100644
--- a/css/styles.scss
+++ b/src/index.scss
@@ -1,9 +1,13 @@
-@import "fonts/cormant_garamont.css";
-//@import "fonts/crimson_pro.css";
+@import "variables";
-:root {
- --header-font: "Cormorant Garamond", sans-serif;
- --body-font: "Crimson Pro", sans-serif;
+#root {
+ padding: 0;
+ margin: 0;
+
+ width: 100%;
+ height: 100%;
+
+ display: flex;
}
body {
@@ -22,7 +26,7 @@ body {
color: #d78453;
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 {
@@ -75,31 +79,6 @@ a {
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) {
body {
flex-direction: column;
@@ -157,12 +136,24 @@ a {
border-radius: 5px;
}
+ a.more {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+
+ img {
+ --hw: 23px;
+ height: var(--hw);
+ width: var(--hw);
+ }
+ }
+
.detailbox {
display: flex;
//align-items: center;
gap: 7px;
- img,svg {
+ img, svg {
--hw: 23px;
height: var(--hw);
width: var(--hw);
diff --git a/src/main.tsx b/src/main.tsx
new file mode 100644
index 0000000..46c0846
--- /dev/null
+++ b/src/main.tsx
@@ -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(
+
+
+ ,
+)
diff --git a/src/pages/Main.tsx b/src/pages/Main.tsx
new file mode 100644
index 0000000..0b4bde0
--- /dev/null
+++ b/src/pages/Main.tsx
@@ -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 (
+ <>
+
+
+ >
+ );
+}
+
+export default Main;
\ No newline at end of file
diff --git a/src/types/MapLocation.ts b/src/types/MapLocation.ts
new file mode 100644
index 0000000..fd4af6d
--- /dev/null
+++ b/src/types/MapLocation.ts
@@ -0,0 +1,19 @@
+export interface MapLocation {
+ name: string;
+ description?: string;
+ image?: MapLocationImage;
+ url?: string;
+ icon?: string;
+ position: MapLocationPosition;
+}
+
+export interface MapLocationImage {
+ name?: string;
+ url: string;
+ credit?: string;
+}
+
+export interface MapLocationPosition {
+ x: string;
+ y: string;
+}
\ No newline at end of file
diff --git a/src/types/MapRegion.ts b/src/types/MapRegion.ts
new file mode 100644
index 0000000..e6ed748
--- /dev/null
+++ b/src/types/MapRegion.ts
@@ -0,0 +1,18 @@
+export interface MapRegion {
+ name: string;
+ description?: string;
+ capital?: string;
+ ruler?: string;
+ population?: string;
+ url?: string;
+ image?: MapRegionImage;
+ borderColor?: string;
+ fillColor?: string;
+ points: string;
+}
+
+export interface MapRegionImage {
+ name?: string;
+ url: string;
+ credit?: string;
+}
\ No newline at end of file
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000..5a2def4
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "Bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["src"]
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..1ffef60
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..9dad701
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["ES2023"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "Bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUncheckedSideEffectImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..8b0f57b
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vite.dev/config/
+export default defineConfig({
+ plugins: [react()],
+})