Compare commits

...
7 Commits
10 changed files with 125 additions and 1508 deletions

No files matched your search

+1 -1
View File
@@ -113,7 +113,7 @@ const registerGuest = async () => {
:icon="['fas', 'circle-exclamation']" :icon="['fas', 'circle-exclamation']"
class="px-1 text-sm" class="px-1 text-sm"
/> />
<span>建議使用電腦全螢幕執行</span> <span>{{ t('authform.recommand_pc_fullscreen') }}</span>
</div> </div>
<form @submit.prevent="handleSubmit()" class="w-full"> <form @submit.prevent="handleSubmit()" class="w-full">
<div v-if="socialLogin && hasSocialLogins"> <div v-if="socialLogin && hasSocialLogins">
+1 -1
View File
@@ -59,7 +59,7 @@ onMounted(async () => {
}) })
questInstruction.value = quest.instruction questInstruction.value = quest.instruction
} catch (error) { } catch (error) {
toast.error('Failed to load quest detail:', error) toast.error(t('quest.load_quest_instruction_failed'), error)
} }
handleColour() handleColour()
}) })
+2 -2
View File
@@ -99,8 +99,8 @@ async function computeGraphData() {
graphData.value = { nodes, edges } graphData.value = { nodes, edges }
} catch (error) { } catch (error) {
console.error('Error computing graph data:', error) console.error(t('quest_map.compute_graph_failed'), error)
toast.error('Failed to load quest data') toast.error(t('quest_map.load_quest_data_failed'))
} }
} }
function handleNodeClick(node: Node) { function handleNodeClick(node: Node) {
+7 -5
View File
@@ -32,7 +32,7 @@ const backtoMap = async () => {
try { try {
router.push({ name: 'map' }) router.push({ name: 'map' })
} catch (err) { } catch (err) {
toast.error('無法讀取地圖') toast.error(t('quest_map.load_quest_map_failed'))
console.error(err) console.error(err)
} }
} }
@@ -52,7 +52,7 @@ setTimeout(() => {
id="QuestCompleted" id="QuestCompleted"
class="text-2xl text-text mb-5 w-full inline-flex justify-center" class="text-2xl text-text mb-5 w-full inline-flex justify-center"
> >
關卡完成! {{ t('game.quest_completed') }}
</h2> </h2>
<div class="z-10 right-1/2 top-1/2" @animationend="defineComponent"> <div class="z-10 right-1/2 top-1/2" @animationend="defineComponent">
<Vue3Lottie <Vue3Lottie
@@ -61,16 +61,18 @@ setTimeout(() => {
:width="200" :width="200"
/> />
</div> </div>
<p class="text-base text-text text-center">恭喜你完成這一關!</p>
<p class="text-base text-text text-center"> <p class="text-base text-text text-center">
接下來回到地圖,迎接新的挑戰吧! {{ t('game.quest_completed_desc_1') }}
</p>
<p class="text-base text-text text-center">
{{ t('game.quest_completed_desc_2') }}
</p> </p>
<a <a
id="BacktoMap" id="BacktoMap"
target="_blank" target="_blank"
@click="backtoMap" @click="backtoMap"
class="inline-flex justify-center rounded-lg text-base font-black py-2 mt-3 bg-text-primary w-full" class="inline-flex justify-center rounded-lg text-base font-black py-2 mt-3 bg-text-primary w-full"
>回到地圖</a >{{ t('game.back_to_map') }}</a
> >
</div> </div>
<div style="position: relative; height: 100vh; overflow: auto"> <div style="position: relative; height: 100vh; overflow: auto">
+12 -4
View File
@@ -52,7 +52,8 @@
"already_registered": "Already have an account?", "already_registered": "Already have an account?",
"not_registered": "Don't have an account?", "not_registered": "Don't have an account?",
"continue_as_guest": "Continue as Guest", "continue_as_guest": "Continue as Guest",
"password_rules": "At least 8 characters, including uppercase and lowercase letters and numbers" "password_rules": "At least 8 characters, including uppercase and lowercase letters and numbers",
"recommand_pc_fullscreen": "Recommended to use desktop version in full-screen mode"
}, },
"authform_error": { "authform_error": {
"too_many_requests": "Too many requests, please try again in 2 minutes", "too_many_requests": "Too many requests, please try again in 2 minutes",
@@ -76,11 +77,14 @@
"quest_map": { "quest_map": {
"title": "Quest Map", "title": "Quest Map",
"intro": "Embark on your Linux adventure!", "intro": "Embark on your Linux adventure!",
"load_quest_map_failed": "Failed to Load Quest Map" "load_quest_map_failed": "Failed to Load Quest Map",
"compute_graph_failed": "Error computing graph data: ",
"load_quest_data_failed": "Failed to Load Quest Data"
}, },
"quest": { "quest": {
"start": "Start Adventure", "start": "Start Adventure",
"locked": "Quest not unlocked" "locked": "Quest not unlocked",
"load_quest_instruction_failed": "Failed to Load Quest Instruction: "
}, },
"leaderboard": { "leaderboard": {
"title": "Leaderboard", "title": "Leaderboard",
@@ -103,6 +107,10 @@
"cheatsheets": "Cheat Sheets", "cheatsheets": "Cheat Sheets",
"reset_to_apply_language": "Reset quest to apply language changes", "reset_to_apply_language": "Reset quest to apply language changes",
"reset_failed": "Reset failed", "reset_failed": "Reset failed",
"language_unavailable": "This quest does not support the selected language, please choose another language" "language_unavailable": "This quest does not support the selected language, please choose another language",
"quest_completed": "Quest Completed",
"quest_completed_desc_1": "Congratulations! You have completed this quest!",
"quest_completed_desc_2": "Return to the map to face new challenges!",
"back_to_map": "Back to Map"
} }
} }
+12 -4
View File
@@ -52,7 +52,8 @@
"already_registered": "已經有帳號了嗎?", "already_registered": "已經有帳號了嗎?",
"not_registered": "還沒有帳號嗎?", "not_registered": "還沒有帳號嗎?",
"continue_as_guest": "以訪客身分繼續", "continue_as_guest": "以訪客身分繼續",
"password_rules": "至少 8 個字元,包含數字及大小寫字母" "password_rules": "至少 8 個字元,包含數字及大小寫字母",
"recommand_pc_fullscreen": "建議使用電腦版全螢幕操作"
}, },
"authform_error": { "authform_error": {
"too_many_requests": "太多請求,兩分鐘後再試一次", "too_many_requests": "太多請求,兩分鐘後再試一次",
@@ -76,11 +77,14 @@
"quest_map": { "quest_map": {
"title": "關卡地圖", "title": "關卡地圖",
"intro": "踏上你的Linux冒險之旅吧!", "intro": "踏上你的Linux冒險之旅吧!",
"load_quest_map_failed": "無法讀取關卡地圖" "load_quest_map_failed": "無法讀取關卡地圖",
"compute_graph_failed": "計算關卡地圖時出錯:",
"load_quest_data_failed": "無法讀取關卡"
}, },
"quest": { "quest": {
"start": "開始冒險", "start": "開始冒險",
"locked": "關卡尚未解鎖" "locked": "關卡尚未解鎖",
"load_quest_instruction_failed": "無法讀取關卡說明:"
}, },
"leaderboard": { "leaderboard": {
"title": "排行榜", "title": "排行榜",
@@ -103,6 +107,10 @@
"cheatsheets": "指令列表", "cheatsheets": "指令列表",
"reset_to_apply_language": "重置關卡以套用語言變更", "reset_to_apply_language": "重置關卡以套用語言變更",
"reset_failed": "重置失敗", "reset_failed": "重置失敗",
"language_unavailable": "此關卡不支援所選語言,請選擇其他語言" "language_unavailable": "此關卡不支援所選語言,請選擇其他語言",
"quest_completed": "關卡完成",
"quest_completed_desc_1": "恭喜你完成了這個關卡!",
"quest_completed_desc_2": "回到地圖,迎接新的挑戰吧!",
"back_to_map": "回到地圖"
} }
} }
+11 -6
View File
@@ -1,10 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { isValidUsername } from '../../../packages/utils' import { isValidUsername } from '../../../packages/utils'
import AuthForm from '../components/AuthForm.vue' import AuthForm from '../components/AuthForm.vue'
import Background from '../components/DynamicBackground.vue' import DynamicBackground from '../components/DynamicBackground.vue'
import HeaderPart from '../components/header/HeaderPart.vue'
import { TooManyRequestsError, ValidationError } from '../utils/errors' import { TooManyRequestsError, ValidationError } from '../utils/errors'
import { checkUsername, chooseUsername } from '../utils/auth' import { checkUsername, chooseUsername } from '../utils/auth'
const { t } = useI18n()
async function check({ async function check({
username, username,
error, error,
@@ -15,21 +19,21 @@ async function check({
}) { }) {
if (username) { if (username) {
if (!isValidUsername(username)) { if (!isValidUsername(username)) {
error('無效的帳號名稱') error(t('authform_error.invalid_username'))
return return
} }
try { try {
await checkUsername(username) await checkUsername(username)
} catch (err) { } catch (err) {
if (err instanceof TooManyRequestsError) { if (err instanceof TooManyRequestsError) {
error('太多請求,兩分鐘後再試一次。') error(t('authform_error.too_many_requests'))
return return
} }
if (err instanceof ValidationError) { if (err instanceof ValidationError) {
error(err.message) error(err.message)
return return
} }
error('出了點問題,請再試一次。') error(t('authform_error.auth_failed'))
} }
} }
} }
@@ -49,7 +53,7 @@ async function handleSubmit({
success() success()
} catch (err: any) { } catch (err: any) {
if (err instanceof TooManyRequestsError) { if (err instanceof TooManyRequestsError) {
error('太多請求,兩分鐘後再試一次。') error(t('authform_error.too_many_requests'))
return return
} }
if (err instanceof ValidationError) { if (err instanceof ValidationError) {
@@ -63,10 +67,11 @@ async function handleSubmit({
<template> <template>
<div class="w-screen h-screen"> <div class="w-screen h-screen">
<Background class="w-full h-full" /> <DynamicBackground class="w-full h-full" />
<div <div
class="h-screen w-screen absolute top-0 left-0 flex flex-wrap justify-center content-center" class="h-screen w-screen absolute top-0 left-0 flex flex-wrap justify-center content-center"
> >
<HeaderPart />
<div class="w-fit"> <div class="w-fit">
<AuthForm <AuthForm
@onSubmit="handleSubmit" @onSubmit="handleSubmit"
+1 -1
View File
@@ -85,7 +85,7 @@ async function check({
return return
} }
console.error(err) console.error(err)
error(t('authform_error.registration_failed')) error(t('authform_error.auth_failed'))
} }
} }
</script> </script>
+5 -4
View File
@@ -55,8 +55,9 @@
"vue-eslint-parser": "^9.4.2", "vue-eslint-parser": "^9.4.2",
"zod-to-json-schema": "^3.24.5" "zod-to-json-schema": "^3.24.5"
}, },
"dependencies": { "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"latest": "^0.2.0" "resolutions": {
}, "**/@mapbox/node-pre-gyp/tar": "^7.5.19",
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" "**/@cypress/request/form-data": "^2.5.4"
}
} }
+73 -1480
View File
File diff suppressed because it is too large. Load diff