Files
echoes-of-the-ash/web-map/index.html

870 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Echoes of the Ashes - Interactive World Map</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
color: #e0e0e0;
overflow: hidden;
}
.container {
display: grid;
grid-template-columns: 1fr 450px;
height: 100vh;
gap: 0;
}
.map-section {
display: flex;
flex-direction: column;
background: #0f0f1e;
border-right: 2px solid #2a2a4a;
}
.header {
padding: 20px 30px;
background: linear-gradient(135deg, #2a2a4a 0%, #1a1a3e 100%);
border-bottom: 2px solid #3a3a6a;
}
h1 {
font-size: 2em;
margin-bottom: 5px;
color: #ffa726;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.subtitle {
font-size: 0.9em;
opacity: 0.7;
}
.bot-link {
display: inline-flex;
align-items: center;
gap: 8px;
margin-top: 10px;
padding: 8px 16px;
background: linear-gradient(135deg, #0088cc 0%, #006699 100%);
color: #ffffff;
text-decoration: none;
border-radius: 20px;
font-size: 0.9em;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 136, 204, 0.3);
}
.bot-link:hover {
background: linear-gradient(135deg, #00a0e6 0%, #0088cc 100%);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 136, 204, 0.5);
}
.bot-link:active {
transform: translateY(0);
}
.bot-link-icon {
font-size: 1.2em;
}
.canvas-wrapper {
flex: 1;
position: relative;
overflow: hidden;
}
#mapCanvas {
width: 100%;
height: 100%;
cursor: grab;
}
#mapCanvas:active {
cursor: grabbing;
}
.controls {
position: absolute;
top: 20px;
right: 20px;
background: rgba(42, 42, 74, 0.9);
padding: 15px;
border-radius: 10px;
border: 1px solid #3a3a6a;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
.controls button {
display: block;
width: 40px;
height: 40px;
margin: 5px 0;
background: #3a3a6a;
border: none;
border-radius: 5px;
color: #ffa726;
font-size: 1.2em;
cursor: pointer;
transition: all 0.2s;
}
.controls button:hover {
background: #ffa726;
color: #1a1a3e;
transform: scale(1.1);
}
.info-panel {
display: flex;
flex-direction: column;
background: #16162e;
overflow-y: auto;
}
.info-section {
padding: 20px;
border-bottom: 1px solid #2a2a4a;
}
.info-section h2 {
color: #ffa726;
margin-bottom: 15px;
font-size: 1.3em;
display: flex;
align-items: center;
gap: 10px;
}
.info-section h3 {
color: #80cbc4;
margin: 15px 0 10px 0;
font-size: 1.1em;
}
.location-image {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
border-radius: 10px;
margin-bottom: 15px;
border: 2px solid #3a3a6a;
}
.image-placeholder {
width: 100%;
aspect-ratio: 4 / 3;
background: linear-gradient(135deg, #2a2a4a 0%, #1a1a3e 100%);
border-radius: 10px;
margin-bottom: 15px;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid #3a3a6a;
color: #5a5a7a;
font-size: 3em;
}
.interactable-image,
.enemy-image {
width: 60px;
height: 45px;
object-fit: cover;
border-radius: 5px;
border: 2px solid #3a3a6a;
}
.interactable-image-placeholder,
.enemy-image-placeholder {
width: 60px;
height: 45px;
background: linear-gradient(135deg, #2a2a4a 0%, #1a1a3e 100%);
border-radius: 5px;
border: 2px solid #3a3a6a;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5em;
color: #5a5a7a;
}
.description {
padding: 10px;
background: rgba(42, 42, 74, 0.3);
border-radius: 5px;
margin-bottom: 15px;
font-size: 0.95em;
line-height: 1.5;
}
.connections {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: 10px;
}
.connection-item {
background: rgba(42, 42, 74, 0.5);
padding: 8px 12px;
border-radius: 5px;
font-size: 0.9em;
border-left: 3px solid #80cbc4;
}
.interactable-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.interactable-card {
background: rgba(42, 42, 74, 0.3);
padding: 15px;
border-radius: 8px;
border: 1px solid #3a3a6a;
}
.interactable-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.interactable-icon {
flex-shrink: 0;
}
.interactable-name {
flex: 1;
font-weight: bold;
color: #ffa726;
}
.action-item {
background: rgba(58, 58, 106, 0.3);
padding: 10px;
border-radius: 5px;
margin: 8px 0;
font-size: 0.85em;
}
.action-header {
font-weight: bold;
color: #80cbc4;
margin-bottom: 5px;
}
.outcome-item {
padding: 5px 10px;
margin: 3px 0;
border-left: 2px solid #5a5a7a;
padding-left: 10px;
}
.outcome-success {
border-left-color: #4caf50;
}
.outcome-failure {
border-left-color: #ff9800;
}
.outcome-critical {
border-left-color: #f44336;
}
.enemy-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.enemy-card {
background: rgba(74, 42, 42, 0.3);
padding: 12px;
border-radius: 8px;
border: 1px solid #6a3a3a;
}
.enemy-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.enemy-icon {
flex-shrink: 0;
}
.enemy-emoji {
font-size: 1.2em;
}
.enemy-name {
flex: 1;
font-weight: bold;
color: #ff5252;
}
.enemy-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-top: 8px;
font-size: 0.85em;
}
.stat-item {
background: rgba(58, 58, 106, 0.3);
padding: 5px 10px;
border-radius: 3px;
}
.legend {
padding: 15px;
background: rgba(42, 42, 74, 0.3);
border-radius: 8px;
}
.legend-item {
display: flex;
align-items: center;
gap: 10px;
margin: 8px 0;
font-size: 0.9em;
}
.legend-color {
width: 30px;
height: 20px;
border-radius: 3px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-top: 15px;
}
.stat-card {
background: rgba(42, 42, 74, 0.5);
padding: 15px;
border-radius: 8px;
text-align: center;
border: 1px solid #3a3a6a;
}
.stat-value {
font-size: 2em;
font-weight: bold;
color: #ffa726;
display: block;
margin-bottom: 5px;
}
.stat-label {
font-size: 0.85em;
opacity: 0.8;
}
.no-data {
padding: 20px;
text-align: center;
opacity: 0.5;
font-style: italic;
}
/* Image modal/lightbox styles */
.image-modal {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.95);
cursor: pointer;
}
.image-modal.active {
display: flex;
align-items: center;
justify-content: center;
animation: fadeIn 0.2s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.image-modal-content {
max-width: 90%;
max-height: 90vh;
object-fit: contain;
border: 3px solid #ffa726;
border-radius: 10px;
box-shadow: 0 0 30px rgba(255, 167, 38, 0.5);
animation: zoomIn 0.2s ease;
}
@keyframes zoomIn {
from { transform: scale(0.8); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.image-modal-close {
position: absolute;
top: 20px;
right: 30px;
font-size: 40px;
color: #fff;
font-weight: bold;
cursor: pointer;
z-index: 10000;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.8);
transition: all 0.2s;
}
.image-modal-close:hover {
color: #ffa726;
transform: scale(1.2);
}
.image-modal-info {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 10px 20px;
border-radius: 20px;
font-size: 0.9em;
text-align: center;
}
/* Make images clickable */
.location-image,
.interactable-image,
.enemy-image {
cursor: pointer;
transition: all 0.2s;
}
.location-image:hover,
.interactable-image:hover,
.enemy-image:hover {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(255, 167, 38, 0.6);
border-color: #ffa726;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #1a1a2e;
}
::-webkit-scrollbar-thumb {
background: #3a3a6a;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #4a4a7a;
}
/* Mobile Responsive Styles */
@media (max-width: 1024px) {
.container {
grid-template-columns: 1fr 350px;
}
h1 {
font-size: 1.5em;
}
.header {
padding: 15px 20px;
}
}
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
height: 100vh;
}
.map-section {
border-right: none;
min-height: 50vh;
}
.info-panel {
max-height: 50vh;
border-top: 2px solid #2a2a4a;
}
h1 {
font-size: 1.3em;
}
.subtitle {
font-size: 0.8em;
}
.header {
padding: 12px 15px;
}
.bot-link {
font-size: 0.85em;
padding: 6px 12px;
margin-top: 8px;
}
.controls {
top: 10px;
right: 10px;
padding: 10px;
}
.controls button {
width: 35px;
height: 35px;
font-size: 1em;
}
.info-section {
padding: 15px;
}
.info-section h2 {
font-size: 1.1em;
}
.info-section h3 {
font-size: 1em;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.stat-card {
padding: 10px;
}
.stat-value {
font-size: 1.5em;
}
.connections {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
body {
overflow: auto;
}
.container {
display: flex;
flex-direction: column;
height: auto;
min-height: 100vh;
}
.map-section {
height: 60vh;
min-height: 400px;
}
.info-panel {
max-height: none;
height: auto;
}
h1 {
font-size: 1.2em;
}
.header {
padding: 10px 12px;
}
.bot-link {
font-size: 0.8em;
padding: 6px 12px;
margin-top: 6px;
gap: 6px;
}
.bot-link-icon {
font-size: 1em;
}
.controls {
top: 8px;
right: 8px;
padding: 8px;
}
.controls button {
width: 32px;
height: 32px;
font-size: 0.9em;
margin: 3px 0;
}
.info-section {
padding: 12px;
}
.info-section h2 {
font-size: 1em;
margin-bottom: 10px;
}
.info-section h3 {
font-size: 0.95em;
margin: 10px 0 8px 0;
}
.description {
padding: 8px;
font-size: 0.9em;
}
.connection-item {
padding: 6px 10px;
font-size: 0.85em;
}
.interactable-card,
.enemy-card {
padding: 10px;
}
.action-item {
padding: 8px;
font-size: 0.8em;
}
.enemy-stats {
grid-template-columns: 1fr;
gap: 5px;
}
.stat-item {
font-size: 0.85em;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.stat-card {
padding: 8px;
}
.stat-value {
font-size: 1.3em;
}
.stat-label {
font-size: 0.8em;
}
.legend-item {
font-size: 0.85em;
}
/* Modal adjustments for mobile */
.image-modal-content {
max-width: 95%;
max-height: 80vh;
}
.image-modal-close {
top: 10px;
right: 15px;
font-size: 35px;
}
.image-modal-info {
bottom: 10px;
padding: 8px 15px;
font-size: 0.85em;
}
}
/* Landscape orientation on mobile */
@media (max-width: 768px) and (orientation: landscape) {
.container {
grid-template-columns: 1fr 300px;
grid-template-rows: 1fr;
}
.map-section {
min-height: 100vh;
}
.info-panel {
max-height: 100vh;
border-top: none;
border-left: 2px solid #2a2a4a;
}
}
/* Touch-friendly controls */
@media (hover: none) and (pointer: coarse) {
.controls button {
min-width: 40px;
min-height: 40px;
}
.location-image,
.interactable-image,
.enemy-image {
cursor: default;
}
/* Larger tap targets */
.connection-item,
.action-item,
.stat-item {
min-height: 40px;
display: flex;
align-items: center;
}
}
</style>
</head>
<body>
<div class="container">
<div class="map-section">
<div class="header">
<h1>🗺️ Interactive World Map</h1>
<p class="subtitle">Echoes of the Ashes</p>
<a href="https://t.me/echoes_of_the_ash_bot" target="_blank" rel="noopener noreferrer" class="bot-link">
<span class="bot-link-icon">🤖</span>
<span>Play on Telegram</span>
</a>
</div>
<div class="canvas-wrapper">
<canvas id="mapCanvas"></canvas>
<div class="controls">
<button id="zoomIn" title="Zoom In">+</button>
<button id="zoomOut" title="Zoom Out"></button>
<button id="resetView" title="Reset View"></button>
<button id="toggleLabels" title="Toggle Labels">🏷️</button>
</div>
</div>
</div>
<div class="info-panel">
<div class="info-section">
<h2>📍 Location Details</h2>
<div id="locationInfo">
<p class="no-data">Click on a location to see details</p>
</div>
</div>
<div class="info-section">
<h2>🎯 Interactables</h2>
<div id="interactablesInfo">
<p class="no-data">Select a location to see interactables</p>
</div>
</div>
<div class="info-section">
<h2>⚔️ Enemy Encounters</h2>
<div id="enemiesInfo">
<p class="no-data">Select a location to see possible enemies</p>
</div>
</div>
<div class="info-section">
<h2>📊 Map Statistics</h2>
<div id="statsInfo">
<div class="stats-grid">
<div class="stat-card">
<span class="stat-value" id="totalLocations">-</span>
<span class="stat-label">Locations</span>
</div>
<div class="stat-card">
<span class="stat-value" id="totalConnections">-</span>
<span class="stat-label">Routes</span>
</div>
<div class="stat-card">
<span class="stat-value" id="totalInteractables">-</span>
<span class="stat-label">Interactables</span>
</div>
<div class="stat-card">
<span class="stat-value" id="totalEnemies">-</span>
<span class="stat-label">Enemy Types</span>
</div>
</div>
</div>
</div>
<div class="info-section">
<h2>🗺️ Legend</h2>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background: #4fc3f7;"></div>
<span>Safe Zone</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #ffa726;"></div>
<span>Low Danger</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #ff7043;"></div>
<span>Medium Danger</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #e53935;"></div>
<span>High Danger</span>
</div>
</div>
</div>
</div>
</div>
<!-- Image Modal/Lightbox -->
<div id="imageModal" class="image-modal">
<span class="image-modal-close">&times;</span>
<img id="modalImage" class="image-modal-content" alt="Full size image">
<div class="image-modal-info" id="modalInfo">Click anywhere to close</div>
</div>
<script src="map.js"></script>
</body>
</html>