mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
Add: Quest Introduction
This commit is contained in:
1 parent
d002b21aa8
commit
dd67bcb1bd
2 files changed
+162
-9
No files matched your search
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { ref, defineProps, onMounted } from 'vue'
|
||||
import { getQuest } from '../utils/api'
|
||||
import MarkdownText from './MarkdownText.vue'
|
||||
|
||||
const props = defineProps({
|
||||
questTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
questId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
questCompleted: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
questUnlocked: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['closeIntro'])
|
||||
const showIntro = ref(true) // Controls whether the modal is visible or not
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
const { questTitle, questId, questCompleted, questUnlocked } = props
|
||||
const questInstruction = ref('')
|
||||
const questColor = ref('')
|
||||
const questTextColor = ref('')
|
||||
const closeModal = () => {
|
||||
showIntro.value = false
|
||||
emit('closeIntro', true)
|
||||
router.push({ name: 'map' })
|
||||
}
|
||||
const handleQuests = (id: string) => {
|
||||
console.log(id)
|
||||
if (questUnlocked) {
|
||||
router.push({ name: 'game', params: { questId: id } })
|
||||
} else {
|
||||
toast.warning('你還沒完成前一個關卡!')
|
||||
}
|
||||
}
|
||||
const handleColour = () => {
|
||||
if (questCompleted) {
|
||||
questColor.value = '#00ff00'
|
||||
questTextColor.value = '#000000'
|
||||
} else if (questUnlocked) {
|
||||
questColor.value = '#8c8c92'
|
||||
questTextColor.value = '#ffffff'
|
||||
} else {
|
||||
questColor.value = '#505050'
|
||||
questTextColor.value = '#a0a0a0'
|
||||
}
|
||||
}
|
||||
onMounted(async () => {
|
||||
const quest = await getQuest(questId)
|
||||
questInstruction.value = quest.instruction
|
||||
handleColour()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="showIntro" class="modal">
|
||||
<div class="modal-content bg-bg-secondary rounded-lg">
|
||||
<span class="close text-text content-between" @click="closeModal"
|
||||
>×</span
|
||||
>
|
||||
|
||||
<h2
|
||||
id="QuestTitle"
|
||||
class="text-2xl text-text mb-5 w-full inline-flex justify-center"
|
||||
>
|
||||
{{ questTitle }}
|
||||
</h2>
|
||||
<div class="w-full h-3/5 p-8">
|
||||
<div class="px-5 whitespace-pre-wrap">
|
||||
<MarkdownText
|
||||
class="text-text markdown-content"
|
||||
:content="questInstruction"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
id="StartAdventure"
|
||||
target="_blank"
|
||||
@click="handleQuests(questId)"
|
||||
:style="{ backgroundColor: questColor, color: questTextColor }"
|
||||
class="inline-flex justify-center rounded-lg text-base font-black py-3 mt-5 w-full text-lg"
|
||||
>開始冒險</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.modal {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
position: relative;
|
||||
margin: 10% auto;
|
||||
padding: 20px;
|
||||
width: 60%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
font-size: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.markdown-content {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { DAG } from '@linux-odyssey/utils'
|
||||
import { getQuests } from '../utils/api'
|
||||
import useUserProfile from '../store/userProfile'
|
||||
import QuestIntro from './QuestIntro.vue'
|
||||
|
||||
const store = useUserProfile()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const svgWidth = ref(window.innerWidth)
|
||||
@@ -18,7 +17,15 @@ const marginY = 120
|
||||
|
||||
const nodeWidth = 160
|
||||
const nodeHeight = 50
|
||||
|
||||
const opened = ref<Node>({
|
||||
id: '',
|
||||
title: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
index: 0,
|
||||
completed: false,
|
||||
unlocked: false,
|
||||
})
|
||||
type Node = {
|
||||
id: string
|
||||
title: string
|
||||
@@ -101,12 +108,21 @@ async function computeGraphData() {
|
||||
toast.error('Failed to load quest data')
|
||||
}
|
||||
}
|
||||
|
||||
function handleNodeClick(node: { id: string; unlocked: boolean }) {
|
||||
if (node.unlocked) {
|
||||
router.push({ name: 'game', params: { questId: node.id } })
|
||||
} else {
|
||||
toast.warning('你還沒完成前一個關卡!')
|
||||
function handleNodeClick(node: Node) {
|
||||
opened.value = node
|
||||
console.log(opened.value)
|
||||
}
|
||||
function closeIntro(close: boolean) {
|
||||
if (close) {
|
||||
opened.value = {
|
||||
id: '',
|
||||
title: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
index: 0,
|
||||
completed: false,
|
||||
unlocked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +218,14 @@ const edgeStyle = computed(() => {
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<QuestIntro
|
||||
:questTitle="opened.title"
|
||||
:questId="opened.id"
|
||||
:questCompleted="opened.completed"
|
||||
:questUnlocked="opened.unlocked"
|
||||
v-if="opened.id !== ''"
|
||||
@close-intro="closeIntro"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in new issue
Block a user