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 += ` -
- - ${regionCapital} -
- `; - if (regionPopulation) data += ` -
- - ${regionPopulation} -
- `; - if (regionRuler) data += ` -
- - ${regionRuler} -
- `; - 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 += `${imageName ?? locationName}`; - if (url) locationString += `wiki iconWiki`; - - 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 ( + <> + + + {regions.map((region, index) => ( + handleMouseEnterRegion(e, region)} + onMouseMove={handleMouseMove} + onMouseLeave={handleMouseLeave} + /> + ))} + {capitals.map((location, index) => ( + handleMouseEnterLocation(e, location)} + onMouseMove={handleMouseMove} + onMouseLeave={handleMouseLeave} + /> + ))} + {cities.map((location, index) => ( + handleMouseEnterLocation(e, location)} + onMouseMove={handleMouseMove} + onMouseLeave={handleMouseLeave} + /> + ))} + {pois.map((location, index) => ( + handleMouseEnterLocation(e, location)} + onMouseMove={handleMouseMove} + onMouseLeave={handleMouseLeave} + /> + ))} + + {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.image.name + )} + {location.url && ( + + wiki icon + 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 icon + 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()], +})