App.vue (4005B)
1 <script setup lang="ts"> 2 import { ref, onMounted, onBeforeUnmount, watch } from "vue"; 3 import Player from "./components/Player.vue"; 4 import FlagIcon from 'vue3-flag-icons'; 5 import { useI18n } from 'vue-i18n'; 6 import { screenSaver } from "./screen-saver"; 7 import SvgIcon from '@jamescoyle/vue-icon'; 8 import { mdiPlaylistMusic } from '@mdi/js'; 9 10 const MenuButton = ref(false); 11 const isFullscreen = ref(false); 12 const showReloadPopup = ref(false); 13 14 const closeMenu = (event: Event) => { 15 const target = event.target as HTMLElement; 16 if (!target.closest(".menu") && !target.closest(".hamburger_btn")) { 17 MenuButton.value = false; 18 } 19 }; 20 21 const { locale, t } = useI18n(); 22 const changeLanguage = (lang: string) => { 23 locale.value = lang; 24 localStorage.setItem("selectedLanguage", lang); 25 showReloadPopup.value = true; 26 27 setTimeout(() => { 28 showReloadPopup.value = false; 29 }, 3000); 30 }; 31 32 const updateBodyClass = () => { 33 document.body.className = `locale-${locale.value}`; 34 document.title = t('appTitle.name'); 35 }; 36 37 watch(locale, updateBodyClass); 38 39 onMounted(() => { 40 const savedLanguage = localStorage.getItem("selectedLanguage"); 41 if (savedLanguage) { 42 locale.value = savedLanguage; 43 } 44 updateBodyClass(); 45 window.addEventListener("click", closeMenu); 46 screenSaver(); 47 }); 48 49 onBeforeUnmount(() => { 50 window.removeEventListener("click", closeMenu); 51 }); 52 </script> 53 54 <template> 55 <header v-if="!isFullscreen"> 56 <nav> 57 <div class="title_bar"> 58 <p><router-link to="/">{{ $t('appTitle.name') }}</router-link></p> 59 </div> 60 <div class="tracklist_btn"> 61 <router-link to="/tracklist"><SvgIcon type="mdi" :path="mdiPlaylistMusic" /></router-link> 62 </div> 63 <div class="hamburger_btn" @click.stop="MenuButton = !MenuButton"> 64 <span class="line line_01" :class="{ 'btn_line01': MenuButton }"></span> 65 <span class="line line_02" :class="{ 'btn_line02': MenuButton }"></span> 66 <span class="line line_03" :class="{ 'btn_line03': MenuButton }"></span> 67 </div> 68 <div class="menu" :class="{ open: MenuButton }"> 69 <ul> 70 <li><router-link to="/about" @click="MenuButton = false">{{ $t('menu.about') }}</router-link></li> 71 <li><router-link to="/terms" @click="MenuButton = false">{{ $t('menu.terms') }}</router-link></li> 72 <li><router-link to="/policy" @click="MenuButton = false">{{ $t('menu.policy') }}</router-link></li> 73 <li><router-link to="/enquiries" @click="MenuButton = false">{{ $t('menu.enquiries') }}</router-link></li> 74 <li><router-link to="/info" @click="MenuButton = false">{{ $t('menu.info') }}</router-link></li> 75 </ul> 76 <div class="language-switcher"> 77 <button class="language_btn" @click="changeLanguage('ja')"><FlagIcon code="jp" size="20" /></button> 78 <button class="language_btn" @click="changeLanguage('en')"><FlagIcon code="us" size="20" /></button> 79 <button class="language_btn" @click="changeLanguage('zh')"><FlagIcon code="cn" size="20" /></button> 80 <button class="language_btn" @click="changeLanguage('ko')"><FlagIcon code="kr" size="20" /></button> 81 </div> 82 </div> 83 </nav> 84 </header> 85 <div id="screenSaver" class="screen-saver"></div> 86 <router-view /> 87 <Player :isFullscreen="isFullscreen" @update:isFullscreen="isFullscreen = $event" /> 88 89 <div v-if="showReloadPopup" class="reload-popup"> 90 <p>{{ $t('popup.reloadMessage') }}</p> 91 </div> 92 </template> 93 94 <style scoped> 95 .reload-popup { 96 position: fixed; 97 bottom: 20px; 98 right: 20px; 99 background-color: #333; 100 color: #fff; 101 padding: 15px; 102 border-radius: 5px; 103 box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); 104 z-index: 1000; 105 animation: fade-in-out 3s forwards; 106 } 107 108 @keyframes fade-in-out { 109 0% { 110 opacity: 0; 111 transform: translateY(10px); 112 } 113 10% { 114 opacity: 1; 115 transform: translateY(0); 116 } 117 90% { 118 opacity: 1; 119 transform: translateY(0); 120 } 121 100% { 122 opacity: 0; 123 transform: translateY(10px); 124 } 125 } 126 </style>