frontend/app/components/TerminalWindow.vue

137 lines
3.3 KiB
Vue

<template>
<div
class="window-wrapper"
:style="{ top: windowData.y + 'px', left: windowData.x + 'px', width: windowData.width + 'px', height: windowData.height + 'px', zIndex: windowData.zIndex }"
@mousedown="bringToFront"
>
<div class="title-bar" @mousedown.prevent="startDrag">
<span class="title">{{ t(windowData.title) }}</span>
<div class="window-controls">
<button @click.stop="minimize">_</button>
<button @click.stop="close">X</button>
</div>
</div>
<div class="content">
<div class="terminal-section">
<span class="prompt">guest@daniels-mac:~$</span>
<input
v-model="command"
type="text"
class="terminal-input"
@keydown.enter="runCommand"
placeholder="Terminal is for display only"
autofocus
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({ windowData: Object });
const emit = defineEmits(['close', 'minimize', 'bring-to-front', 'update-position']);
const command = ref('');
const runCommand = () => {
console.log(`Command executed: ${command.value}`);
command.value = '';
};
const close = () => emit('close');
const minimize = () => emit('minimize');
const bringToFront = () => emit('bring-to-front');
const startDrag = (event) => {
const startX = event.clientX;
const startY = event.clientY;
const initialX = props.windowData.x;
const initialY = props.windowData.y;
const onMouseMove = (moveEvent) => {
const newX = initialX + (moveEvent.clientX - startX);
const newY = initialY + (moveEvent.clientY - startY);
emit('update-position', { x: newX, y: newY });
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
</script>
<style scoped>
.window-wrapper {
position: absolute;
background-color: #c0c0c0; /* Windows 95 gray */
border: 2px solid;
border-color: #ffffff #808080 #808080 #ffffff;
box-shadow: 2px 2px 5px rgba(0,0,0,0.5);
display: flex;
flex-direction: column;
}
.title-bar {
background-color: #000080; /* Windows 95 blue */
color: white;
padding: 4px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
font-weight: bold;
}
.window-controls button {
background-color: #c0c0c0;
border: 1px solid;
border-color: #ffffff #808080 #808080 #ffffff;
font-weight: bold;
margin-left: 2px;
min-width: 20px;
}
.content {
padding: 10px;
flex-grow: 1;
background-color: black;
color: #34d399; /* green-400 */
font-family: 'Courier New', Courier, monospace;
}
.terminal-section {
display: flex;
align-items: center;
}
.prompt {
color: #fbbF24; /* yellow-400 */
margin-right: 8px;
white-space: nowrap;
}
.terminal-input {
background: transparent;
border: none;
color: #34d399; /* green-400 */
width: 100%;
font-family: 'Courier New', Courier, monospace;
}
.terminal-input:focus {
outline: none;
}
.terminal-input::placeholder {
color: #6b7280; /* gray-500 */
}
</style>