fix: language
This commit is contained in:
parent
9039fb1a57
commit
33835376ba
22
app/app.vue
22
app/app.vue
|
@ -1,6 +1,7 @@
|
|||
<script setup>
|
||||
import Taskbar from '~/components/Taskbar.vue';
|
||||
import AboutMeWindow from '~/components/AboutMeWindow.vue';
|
||||
import TerminalWindow from '~/components/TerminalWindow.vue';
|
||||
import { ref, reactive, onMounted, onUnmounted, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
@ -37,7 +38,7 @@ const saveWindowsToLocalStorage = () => {
|
|||
};
|
||||
|
||||
// Function to open a new window or bring an existing one to front
|
||||
const openWindow = (type, titleKey, initialWidth = 400, initialHeight = 300) => {
|
||||
const openWindow = (type, titleKey, initialWidth = 600, initialHeight = 400) => {
|
||||
const existingWindow = windows.find(w => w.type === type);
|
||||
if (existingWindow) {
|
||||
bringWindowToFront(existingWindow.id);
|
||||
|
@ -51,7 +52,7 @@ const openWindow = (type, titleKey, initialWidth = 400, initialHeight = 300) =>
|
|||
const desktopWidth = window.innerWidth;
|
||||
const desktopHeight = window.innerHeight - 40; // Minus taskbar height
|
||||
const initialX = (desktopWidth - initialWidth) / 2;
|
||||
const initialY = (desktopHeight - initialHeight) / 2 + 40; // Add taskbar height
|
||||
const initialY = (desktopHeight - initialHeight) / 2 + 40; // Offset by taskbar height
|
||||
|
||||
const newWindow = {
|
||||
id: generateUniqueId(),
|
||||
|
@ -129,6 +130,10 @@ const openAboutMeWindow = () => {
|
|||
openWindow('about-me', 'about_me'); // Pass the translation key
|
||||
};
|
||||
|
||||
const openTerminalWindow = () => {
|
||||
openWindow('terminal', 'terminal');
|
||||
};
|
||||
|
||||
// Computed property for minimized windows
|
||||
const minimizedWindows = computed(() => {
|
||||
return windows.filter(win => win.isMinimized);
|
||||
|
@ -145,6 +150,7 @@ onUnmounted(() => {
|
|||
<Taskbar
|
||||
@open-about-me="openAboutMeWindow"
|
||||
@close-all-windows="closeAllWindows"
|
||||
@open-terminal="openTerminalWindow"
|
||||
:minimized-windows="minimizedWindows"
|
||||
@restore-window="restoreWindow"
|
||||
/>
|
||||
|
@ -163,6 +169,15 @@ onUnmounted(() => {
|
|||
@bring-to-front="bringWindowToFront(window.id)"
|
||||
@update-position="updateWindowPosition(window.id, $event.x, $event.y)"
|
||||
/>
|
||||
<TerminalWindow
|
||||
v-if="window.type === 'terminal' && window.isVisible && !window.isMinimized"
|
||||
:window-data="window"
|
||||
@close="closeWindow(window.id)"
|
||||
@minimize="minimizeWindow(window.id)"
|
||||
@restore="restoreWindow(window.id)"
|
||||
@bring-to-front="bringWindowToFront(window.id)"
|
||||
@update-position="updateWindowPosition(window.id, $event.x, $event.y)"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -190,8 +205,7 @@ body {
|
|||
}
|
||||
|
||||
.desktop-content {
|
||||
/* Push content down by the height of the taskbar */
|
||||
margin-top: 40px;
|
||||
margin-top: 40px; /* Push content down by the height of the taskbar */
|
||||
height: calc(100vh - 40px); /* Fill remaining height */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
<span>{{ t('start') }}</span>
|
||||
</button>
|
||||
<div v-if="showStartMenu" class="start-menu">
|
||||
<div class="menu-item" @click="openTerminal">
|
||||
{{ t('terminal') }}
|
||||
</div>
|
||||
<div class="menu-item" @click="openAboutMe">
|
||||
{{ t('about_me') }}
|
||||
</div>
|
||||
|
@ -37,7 +40,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t, locale, setLocale } = useI18n();
|
||||
|
@ -53,12 +56,17 @@ const isMounted = ref(false);
|
|||
let timerId = null;
|
||||
const showStartMenu = ref(false);
|
||||
|
||||
const emit = defineEmits(['open-about-me', 'restore-window', 'close-all-windows']);
|
||||
const emit = defineEmits(['open-about-me', 'restore-window', 'close-all-windows', 'open-terminal']);
|
||||
|
||||
const toggleStartMenu = () => {
|
||||
showStartMenu.value = !showStartMenu.value;
|
||||
};
|
||||
|
||||
const openTerminal = () => {
|
||||
emit('open-terminal');
|
||||
showStartMenu.value = false;
|
||||
};
|
||||
|
||||
const openAboutMe = () => {
|
||||
emit('open-about-me');
|
||||
showStartMenu.value = false;
|
||||
|
@ -79,8 +87,6 @@ const restoreMinimizedWindow = (id) => {
|
|||
emit('restore-window', id);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const updateCurrentTime = () => {
|
||||
// Map i18n locale to a specific locale for time formatting
|
||||
const timeLocale = locale.value === 'zh-tw' ? 'zh-TW' : 'en-US';
|
||||
|
@ -109,8 +115,8 @@ onUnmounted(() => {
|
|||
align-items: center;
|
||||
background-color: #c0c0c0; /* Classic Windows gray */
|
||||
padding: 4px 6px;
|
||||
border: 2px solid;
|
||||
border-color: #ffffff #808080 #808080 #ffffff; /* 3D effect */
|
||||
border-top: 2px solid #ffffff;
|
||||
border-bottom: 2px solid #808080;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
|
@ -179,7 +185,7 @@ onUnmounted(() => {
|
|||
|
||||
.start-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
top: 100%; /* Opens downwards from the taskbar */
|
||||
left: 0;
|
||||
background-color: #c0c0c0;
|
||||
border: 2px solid;
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<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>
|
|
@ -2,25 +2,19 @@
|
|||
<div class="desktop">
|
||||
<div class="icon">
|
||||
<div class="icon-image">[PC]</div>
|
||||
<div class="icon-label">{{ t('my_computer') }}</div>
|
||||
<div class="icon-label">{{ $t('my_computer') }}</div>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<div class="icon-image">[BIN]</div>
|
||||
<div class="icon-label">{{ t('recycle_bin') }}</div>
|
||||
<div class="icon-label">{{ $t('recycle_bin') }}</div>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<div class="icon-image">[>]_</div>
|
||||
<div class="icon-label">{{ t('terminal') }}</div>
|
||||
<div class="icon-label">{{ $t('terminal') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'; // Import useI18n
|
||||
|
||||
const { t } = useI18n(); // Use useI18n composable
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.desktop {
|
||||
display: flex;
|
||||
|
|
Loading…
Reference in New Issue