From bae864c2d0acd2c13d676ed3c4d87875b98eb524 Mon Sep 17 00:00:00 2001 From: fokopies Date: Mon, 9 Feb 2026 22:40:16 +0100 Subject: [PATCH] UI/UX Overhaul: NavBar, Icons, Mobile Menu, and Status Panel Integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Przeniesienie tytułu i wybieraka języka do nowego komponentu NavBar - Integracja biblioteki flag-icons i mapowanie kodów języków na kraje - Wdrożenie biblioteki ikon lucide-vue-next i zastąpienie wszystkich emoji ikonami SVG - Implementacja pełnoekranowego, responsywnego menu mobilnego (hamburger menu) - Przeniesienie przycisków akcji (Reset, Cofnij) do komponentu StatusPanel - Nowy układ panelu statusu (połączone statystyki i akcje w jednym szklanym panelu) - Usunięcie przestarzałych komponentów (GameActions, LevelSelector) - Poprawki wizualne i stylowe (glassmorphism, animacje przejść) --- dev-dist/sw.js | 2 +- package-lock.json | 17 + package.json | 2 + src/App.vue | 470 ++-------------------- src/components/GameActions.vue | 48 --- src/components/Hints.vue | 7 +- src/components/LevelSelector.vue | 67 ---- src/components/NavBar.vue | 654 +++++++++++++++++++++++++++++++ src/components/StatusPanel.vue | 117 +++++- src/main.js | 1 + 10 files changed, 815 insertions(+), 570 deletions(-) delete mode 100644 src/components/GameActions.vue delete mode 100644 src/components/LevelSelector.vue create mode 100644 src/components/NavBar.vue diff --git a/dev-dist/sw.js b/dev-dist/sw.js index ec8107a..e1abb74 100644 --- a/dev-dist/sw.js +++ b/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-5a5d9309'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.vhao5e6obe8" + "revision": "0.eh0stsihuc8" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/package-lock.json b/package-lock.json index a14c4a8..9a148dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.0.0", "dependencies": { "fireworks-js": "^2.10.8", + "flag-icons": "^7.5.0", + "lucide-vue-next": "^0.563.0", "pinia": "^2.1.7", "vue": "^3.4.19" }, @@ -3434,6 +3436,12 @@ "integrity": "sha512-UZNxeJvRmQzLisN4iriWXqKojG9TDJqc0dPmkUw0/+AEQQ3w8z1Jx2YdFSiBGSVb/u4dPTQXU109GMVblzhfpg==", "license": "MIT" }, + "node_modules/flag-icons": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-7.5.0.tgz", + "integrity": "sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg==", + "license": "MIT" + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -4349,6 +4357,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-vue-next": { + "version": "0.563.0", + "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.563.0.tgz", + "integrity": "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA==", + "license": "ISC", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", diff --git a/package.json b/package.json index 79b5232..4400675 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ }, "dependencies": { "fireworks-js": "^2.10.8", + "flag-icons": "^7.5.0", + "lucide-vue-next": "^0.563.0", "pinia": "^2.1.7", "vue": "^3.4.19" }, diff --git a/src/App.vue b/src/App.vue index d63a038..b4f3189 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,9 +3,8 @@ import { computed, onMounted, onUnmounted, ref } from 'vue'; import { usePuzzleStore } from './stores/puzzle'; import { useI18n } from './composables/useI18n'; import GameBoard from './components/GameBoard.vue'; -import LevelSelector from './components/LevelSelector.vue'; +import NavBar from './components/NavBar.vue'; import StatusPanel from './components/StatusPanel.vue'; -import GameActions from './components/GameActions.vue'; import GuidePanel from './components/GuidePanel.vue'; import WinModal from './components/WinModal.vue'; import CustomGameModal from './components/CustomGameModal.vue'; @@ -22,88 +21,8 @@ const installDismissed = ref(false); const isCoarsePointer = ref(false); const isStandalone = ref(false); const themePreference = ref('system'); -const isLangOpen = ref(false); -const langMenuRef = ref(null); let displayModeMedia = null; let prefersColorSchemeMedia = null; -const flagModules = import.meta.glob('./assets/flags/*.svg', { eager: true, as: 'url' }); -const flagMap = Object.fromEntries( - Object.entries(flagModules).map(([path, url]) => [path.split('/').pop().replace('.svg', ''), url]) -); -const flagAliases = { - 'pt-br': 'pt', - 'pt-pt': 'pt', - 'fr-ca': 'fr', - 'nl-be': 'nl', - 'es-es': 'es', - 'es-419': 'es', - 'zh-hans': 'zh', - 'zh-hant': 'zh' -}; -const getFlagUrl = (code) => { - const base = flagAliases[code] || code; - return flagMap[base] || flagMap['globe'] || null; -}; - -const languageFlags = { - en: '', - zh: '', - hi: '', - es: '', - fr: '', - ar: '', - bn: '', - ru: '', - pt: '', - ur: '', - pl: '', - de: '', - it: '', - nl: '', - sv: '', - da: '', - fi: '', - no: '', - cs: '', - sk: '', - hu: '', - ro: '', - bg: '', - el: '', - uk: '', - be: '', - sr: '', - hr: '', - sl: '', - lt: '', - lv: '', - et: '', - ga: '', - is: '', - mt: '', - sq: '', - mk: '', - bs: '', - tr: '', - ca: '', - gl: '', - cy: '', - gd: '', - eu: '' -}; - -const languages = computed(() => { - return locales.value - .map((code) => ({ code, label: t(`language.${code}`) })) - .sort((a, b) => a.label.localeCompare(b.label, locale.value)); -}); - -const searchTerm = ref(''); -const filteredLanguages = computed(() => { - const q = searchTerm.value.trim().toLowerCase(); - if (!q) return languages.value; - return languages.value.filter((l) => l.label.toLowerCase().includes(q) || l.code.includes(q)); -}); const installLabel = computed(() => { return isCoarsePointer.value ? t('pwa.installMobile') : t('pwa.installDesktop'); @@ -165,24 +84,6 @@ const handleSystemThemeChange = () => { } }; -const selectLanguage = (value) => { - setLocale(value); - isLangOpen.value = false; -}; - -const handleOutsideClick = (event) => { - if (!langMenuRef.value) return; - if (!langMenuRef.value.contains(event.target)) { - isLangOpen.value = false; - } -}; - -const handleKeydown = (e) => { - if (e.key === 'Escape') { - isLangOpen.value = false; - } -}; - onMounted(() => { if (!store.loadState()) { store.initGame(); // Inicjalizacja domyślnej gry jeśli brak zapisu @@ -209,8 +110,6 @@ onMounted(() => { } else if (displayModeMedia?.addListener) { displayModeMedia.addListener(updateStandalone); } - document.addEventListener('click', handleOutsideClick); - document.addEventListener('keydown', handleKeydown); } }); @@ -228,73 +127,18 @@ onUnmounted(() => { } else if (displayModeMedia?.removeListener) { displayModeMedia.removeListener(updateStandalone); } - document.removeEventListener('click', handleOutsideClick); - document.removeEventListener('keydown', handleKeydown); });