198 lines
4.6 KiB
Vue
198 lines
4.6 KiB
Vue
<template>
|
|
<div v-if="villageData && villageData.tiles" class="village-container">
|
|
<div class="village-grid-wrapper" :style="gridWrapperStyle">
|
|
<!-- Empty corner for alignment -->
|
|
<div class="empty-corner"></div>
|
|
|
|
<!-- Column Labels (A, B, C...) -->
|
|
<div class="col-labels">
|
|
<div class="col-label" v-for="colLabel in colLabels" :key="colLabel">{{ colLabel }}</div>
|
|
</div>
|
|
|
|
<!-- Row Labels (7, 6, 5...) -->
|
|
<div class="row-labels">
|
|
<div class="row-label" v-for="rowLabel in rowLabels" :key="rowLabel">{{ rowLabel }}</div>
|
|
</div>
|
|
|
|
<!-- The actual grid -->
|
|
<div class="village-grid" :style="gridStyle">
|
|
<div
|
|
v-for="tile in villageData.tiles"
|
|
:key="tile.id"
|
|
class="tile"
|
|
:class="tileClasses(tile)"
|
|
:style="{ 'grid-column': tile.x + 1, 'grid-row': gridHeight - tile.y }"
|
|
@click="$emit('tile-click', tile)"
|
|
>
|
|
<span class="tile-content">{{ getTileEmoji(tile) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="loading">
|
|
Загрузка деревни...
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
|
|
// --- Props & Emits ---
|
|
const props = defineProps({
|
|
villageData: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
defineEmits(['tile-click']);
|
|
|
|
// --- Grid Dimensions ---
|
|
const gridWidth = computed(() => {
|
|
if (!props.villageData?.tiles || props.villageData.tiles.length === 0) return 5; // Default
|
|
return Math.max(...props.villageData.tiles.map(t => t.x)) + 1;
|
|
});
|
|
|
|
const gridHeight = computed(() => {
|
|
if (!props.villageData?.tiles || props.villageData.tiles.length === 0) return 7; // Default
|
|
return Math.max(...props.villageData.tiles.map(t => t.y)) + 1;
|
|
});
|
|
|
|
// --- Dynamic Styles ---
|
|
const gridWrapperStyle = computed(() => ({
|
|
'grid-template-columns': `20px repeat(${gridWidth.value}, var(--tile-size))`,
|
|
'grid-template-rows': `repeat(${gridHeight.value}, var(--tile-size)) 20px`,
|
|
}));
|
|
|
|
const gridStyle = computed(() => ({
|
|
'grid-template-columns': `repeat(${gridWidth.value}, var(--tile-size))`,
|
|
'grid-template-rows': `repeat(${gridHeight.value}, var(--tile-size))`,
|
|
}));
|
|
|
|
// --- Labels ---
|
|
const colLabels = computed(() => {
|
|
return Array.from({ length: gridWidth.value }, (_, i) => String.fromCharCode(65 + i));
|
|
});
|
|
|
|
const rowLabels = computed(() => {
|
|
return Array.from({ length: gridHeight.value }, (_, i) => gridHeight.value - i);
|
|
});
|
|
|
|
|
|
// --- Tile Display Logic ---
|
|
const getTileEmoji = (tile) => {
|
|
if (tile.terrainState === 'CLEARING') return '⏳';
|
|
if (tile.object) {
|
|
switch (tile.object.type) {
|
|
case 'HOUSE': return '🏠';
|
|
case 'FIELD': return '🌱';
|
|
case 'LUMBERJACK': return '🪓';
|
|
case 'QUARRY': return '⛏️';
|
|
case 'WELL': return '💧';
|
|
default: return '❓';
|
|
}
|
|
}
|
|
switch (tile.terrainType) {
|
|
case 'BLOCKED_TREE': return '🌳';
|
|
case 'BLOCKED_STONE': return '🪨';
|
|
case 'EMPTY': return '';
|
|
default: return '❓';
|
|
}
|
|
};
|
|
|
|
const tileClasses = (tile) => {
|
|
return {
|
|
'tile-blocked': tile.terrainType === 'BLOCKED_TREE' || tile.terrainType === 'BLOCKED_STONE',
|
|
'tile-object': !!tile.object,
|
|
'tile-empty': tile.terrainType === 'EMPTY' && !tile.object,
|
|
};
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.village-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 100%;
|
|
padding: 0 10px;
|
|
margin-top: 20px;
|
|
--tile-size: clamp(40px, 10vw, 55px);
|
|
}
|
|
|
|
.village-grid-wrapper {
|
|
display: grid;
|
|
gap: 4px;
|
|
padding: 4px;
|
|
width: fit-content;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.empty-corner {
|
|
grid-column: 1;
|
|
grid-row: 8;
|
|
}
|
|
|
|
.col-labels {
|
|
grid-column: 2 / -1;
|
|
grid-row: 8;
|
|
display: flex;
|
|
justify-content: space-around;
|
|
color: #999;
|
|
}
|
|
|
|
.row-labels {
|
|
grid-column: 1;
|
|
grid-row: 1 / 8;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-around;
|
|
align-items: center;
|
|
color: #999;
|
|
}
|
|
|
|
.col-label, .row-label {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.village-grid {
|
|
grid-column: 2 / -1;
|
|
grid-row: 1 / 8;
|
|
display: grid;
|
|
gap: 4px;
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.tile {
|
|
width: var(--tile-size);
|
|
height: var(--tile-size);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 4px;
|
|
background-color: #f9f9f9;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.tile.tile-blocked {
|
|
background-color: #f3f4f6;
|
|
}
|
|
|
|
.tile.tile-object {
|
|
background-color: #ecfdf5;
|
|
}
|
|
|
|
.tile.tile-empty:hover {
|
|
background-color: #fefce8;
|
|
border-color: #facc15;
|
|
}
|
|
|
|
.tile-content {
|
|
font-size: calc(var(--tile-size) * 0.4);
|
|
}
|
|
</style>
|