Compare commits

...
Author SHA1 Message Date
Annie Huang 5069ac12da fix map view 2024-04-11 23:39:57 +08:00
Lin, Hung-Shin cec4d86058 build(deps): bump tar from 6.2.0 to 6.2.1 (#131)
Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/isaacs/node-tar/commit/bef7b1e4ffab822681fea2a9b22187192ed14717"><code>bef7b1e</code></a>
6.2.1</li>
<li><a
href="https://github.com/isaacs/node-tar/commit/fe8cd57da5686f8695415414bda49206a545f7f7"><code>fe8cd57</code></a>
prevent extraction in excessively deep subfolders</li>
<li><a
href="https://github.com/isaacs/node-tar/commit/fe7ebfdcede1f8a2e65db12e19ecc4b3a9934648"><code>fe7ebfd</code></a>
remove security.md</li>
<li>See full diff in <a
href="https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tar&package-manager=npm_and_yarn&previous-version=6.2.0&new-version=6.2.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/linux-odyssey/linux-odyssey/network/alerts).

</details>
2024-04-11 22:39:51 +08:00
dependabot[bot] 93b0bae204 build(deps): bump tar from 6.2.0 to 6.2.1
Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-11 11:56:58 +00:00
Lin, Hung-Shin 4713b11c95 Fix e2e Testing (#130)
**Fix e2e broken caused by website modification**

- Add back "GameTitle" for **Linux Odyssey** in header
- Delete echo hint in quest **move** (It stucks the testing)
- Modify paths for several testing describes
- Fix type problems in command.ts
2024-04-11 15:19:38 +08:00
Annie Huang 36e6bc10d3 fix: e2e broken caused by website modification 2024-04-09 11:32:58 +08:00
Annie Huang 580d5fc3f8 Feat landing page - Mobile Optimisation (#112)
This optimisation is for mobile usage and also make header a better
component.
- Header Restruction
- Menu pop up when using smaller screen
- Seperate header components and other components
2024-04-07 23:49:53 +08:00
Annie Huang d8392ec3f6 delete redundant code 2024-04-07 23:44:41 +08:00
Annie Huang 5f99f42f5f fix type problems 2024-04-07 20:41:17 +08:00
Annie Huang bdf757c2d4 fix: header components in the middle 2024-04-07 20:40:44 +08:00
Annie Huang 453bfb7f1e delete redundant code 2024-04-06 22:06:48 +08:00
wancat 3b470ed952 fix: session store type 2024-04-06 22:06:48 +08:00
Annie Huang b4af2d46d3 fix hint display problems 2024-04-06 22:06:48 +08:00
Annie Huang 0e96e30b96 categorise components 2024-04-06 22:06:48 +08:00
Annie Huang 3e3ac58c6b Restruct heading 2024-04-06 22:06:48 +08:00
wancat 9f690548cf fix: session store type 2024-04-06 22:06:48 +08:00
Annie Huang cd2ec6df75 fix hint display problems 2024-04-06 22:06:48 +08:00
Annie Huang 8e7b5f2552 modify menu position while open 2024-04-06 22:06:48 +08:00
Annie Huang 385c6bc110 delete testing id 2024-04-06 22:06:48 +08:00
wancat 092cf284dd fix: session store type 2024-04-06 22:06:48 +08:00
Annie Huang 7806852cab fix hint display problems 2024-04-06 22:06:48 +08:00
Annie Huang 1e31cf3be5 fix file locations and transfer to ts 2024-04-06 22:06:29 +08:00
Annie Huang aa903fbacf fix file position 2024-04-06 22:06:29 +08:00
Annie Huang df980a7d56 delete redundant code 2024-04-06 22:06:29 +08:00
Annie Huang 980d0497f4 fix header justify end property 2024-04-06 22:06:29 +08:00
Annie Huang e37a23c34f mobile menu (but not justify end while bigger screen, still solving) 2024-04-06 22:06:29 +08:00
Annie Huang f4fc6de4cc canceling [..vh] 2024-04-06 22:06:29 +08:00
Annie Huang 9bfc6614ca hide some text when screen is small 2024-04-06 22:06:29 +08:00
Annie Huang 8c4a9ea871 add header to login and register page, modified header class but not fit for all circumstances 2024-04-06 22:06:29 +08:00
Annie Huang ad29137b86 categorise components - change path 2024-04-06 22:06:29 +08:00
Annie Huang b5e49547ea categorise components 2024-04-06 22:06:29 +08:00
Annie Huang 9a4f9b958a Restruct heading 2024-04-06 22:06:29 +08:00
Annie Huang 29602785cd rwd player opinions 2024-04-06 22:05:59 +08:00
22 changed files with 337 additions and 177 deletions

No files matched your search

+1 -1
View File
@@ -177,7 +177,7 @@ onMounted(async () => {
class="p-2 stroke-2 scale-y-120 justify-center items-center" class="p-2 stroke-2 scale-y-120 justify-center items-center"
/> />
<h1 <h1
class="p-4 absolute w-fit z-2 font-mono flex flax-wrap text-xl" class="p-10 absolute w-fit z-2 font-mono flex flax-wrap text-xl"
style="width: 30%; height: 6%; font-size: 3vh; color: #00ff00" style="width: 30%; height: 6%; font-size: 3vh; color: #00ff00"
> >
踏上你的Linux冒險之旅吧! 踏上你的Linux冒險之旅吧!
@@ -2,6 +2,6 @@
<font-awesome-icon :icon="['fas', 'list']" class="text-text-primary p-1" /> <font-awesome-icon :icon="['fas', 'list']" class="text-text-primary p-1" />
<h1 id="CommandBook" class="inline text-text-primary font-xl">指令之書</h1> <h1 id="CommandBook" class="inline text-text-primary font-xl">指令之書</h1>
<div id="cheatsheets"> <div id="cheatsheets">
<p class="text-text-secondary">--指令列表--</p> <p class="text-text-secondary">-- --指令列表-- --</p>
</div> </div>
</template> </template>
@@ -4,7 +4,7 @@ import { useToast } from 'vue-toastification'
import { ref } from 'vue' import { ref } from 'vue'
import { Vue3Lottie } from 'vue3-lottie' import { Vue3Lottie } from 'vue3-lottie'
// import { surveyUrl } from '../config' // import { surveyUrl } from '../config'
import CompleteAnimation from '../img/complete-animation.json' import CompleteAnimation from '../../img/complete-animation.json'
const showModal = ref(true) // Controls whether the modal is visible or not const showModal = ref(true) // Controls whether the modal is visible or not
const router = useRouter() const router = useRouter()
@@ -26,7 +26,6 @@ const backtoMap = async () => {
try { try {
router.push({ name: 'map' }) router.push({ name: 'map' })
} catch (err) { } catch (err) {
// useToast().error('Failed to load map')
toast.error('無法讀取地圖') toast.error('無法讀取地圖')
console.error(err) console.error(err)
} }
@@ -60,17 +59,6 @@ setTimeout(() => {
<p class="text-base text-text text-center"> <p class="text-base text-text text-center">
接下來回到地圖,迎接新的挑戰吧! 接下來回到地圖,迎接新的挑戰吧!
</p> </p>
<!-- <p class="text-base text-text">
您已成功完成挑戰,真的非常感謝您的參與!<br />
如果您能撥冗填寫這份問卷,我們將不勝感激,這對我們非常重要!
</p> -->
<!-- <a
id="SurveyButton"
:href="surveyUrl"
target="_blank"
class="inline-flex justify-center rounded-lg text-base font-black py-2 mt-3 bg-text-primary w-full"
>填寫問卷</a
> -->
<a <a
id="BacktoMap" id="BacktoMap"
target="_blank" target="_blank"
@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
import { createSession } from '../store/session' import { createSession } from '../../store/session'
import { surveyUrl } from '../config' import { surveyUrl } from '../../config'
const router = useRouter() const router = useRouter()
const reset = async () => { const reset = async () => {
@@ -20,29 +20,31 @@ const continuePlay = async () => {
</script> </script>
<template> <template>
<section class="h-[10%] p-3 grid grid-cols-4 gap-4 place-content-between"> <section
class="h-fit w-fit px-1 py-1 grid grid-cols-4 gap-2 place-content-between"
>
<button id="survey" class="bg-bg-secondary rounded-lg p-2"> <button id="survey" class="bg-bg-secondary rounded-lg p-2">
<a title="Survey" :href="surveyUrl" target="_blank" class="h-5 w-5"> <a title="Survey" :href="surveyUrl" target="_blank" class="h-5 w-5">
<font-awesome-icon <font-awesome-icon
:icon="['fas', 'file-invoice']" :icon="['fas', 'file-invoice']"
class="text-text-primary" class="text-text-primary px-1"
/> />
<p class="text-text-primary inline ml-1">問卷</p> <p class="text-text-primary inline ml-1 hidden md:flex">問卷</p>
</a> </a>
</button> </button>
<button disabled id="solution" class="bg-bg-disabled rounded-lg p-2"> <button disabled id="solution" class="bg-bg-disabled rounded-lg p-2">
<font-awesome-icon <font-awesome-icon
:icon="['far', 'circle-question']" :icon="['far', 'circle-question']"
class="text-text-disabled" class="text-text-disabled px-1"
/> />
<p class="text-text-disabled inline ml-1">解答</p> <p class="text-text-disabled inline ml-1 hidden md:flex">解答</p>
</button> </button>
<button id="reset" class="bg-bg-secondary rounded-lg p-2" @click="reset"> <button id="reset" class="bg-bg-secondary rounded-lg p-2" @click="reset">
<font-awesome-icon <font-awesome-icon
:icon="['fas', 'arrow-rotate-left']" :icon="['fas', 'arrow-rotate-left']"
class="text-text-primary" class="text-text-primary px-1"
/> />
<p class="text-text-primary inline ml-1">重來</p> <p class="text-text-primary inline ml-1 hidden md:flex">重來</p>
</button> </button>
<button <button
id="continue" id="continue"
@@ -51,9 +53,9 @@ const continuePlay = async () => {
> >
<font-awesome-icon <font-awesome-icon
:icon="['far', 'circle-right']" :icon="['far', 'circle-right']"
class="text-text-primary" class="text-text-primary px-1"
/> />
<p class="text-text-primary inline ml-1">繼續</p> <p class="text-text-primary inline ml-1 hidden md:flex">繼續</p>
</button> </button>
</section> </section>
</template> </template>
@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import sessionStore from '../store/session' import sessionStore from '../../store/session'
import MarkdownText from './MarkdownText.vue' import MarkdownText from '../MarkdownText.vue'
const current = ref(-1) const current = ref(-1)
watch( watch(
@@ -27,16 +27,12 @@ const right = () => {
<template> <template>
<div class="h-full flex flex-col"> <div class="h-full flex flex-col">
<!-- Hint Header -->
<div class="flex items-center p-2 h-10"> <div class="flex items-center p-2 h-10">
<font-awesome-icon <font-awesome-icon
:icon="['far', 'lightbulb']" :icon="['far', 'lightbulb']"
class="text-yellow-200 p-2 content-center" class="text-yellow-200 p-2 content-center"
/> />
<h1 class="inline text-text w-1/2 font-xl p-2 m-1"> <h1 class="inline text-text w-1/2 font-xl p-2 m-1">提示</h1>
<!-- Hint -->
提示
</h1>
<div v-if="current !== -1" class="flex w-full justify-end items-end"> <div v-if="current !== -1" class="flex w-full justify-end items-end">
<button <button
class="p-2 m-1 w-1/8" class="p-2 m-1 w-1/8"
@@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import MarkdownText from './MarkdownText.vue' import MarkdownText from '../MarkdownText.vue'
import sessionStore from '../store/session' import sessionStore from '../../store/session'
import { Task } from '../types' import { Task } from '../../types'
const tasks = computed(() => { const tasks = computed(() => {
return sessionStore.session.tasks.map((task: Task) => { return sessionStore.session.tasks.map((task: Task) => {
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { useTerminal } from '../store/session' import { useTerminal } from '../../store/session'
const terminal = ref<HTMLElement | null>(null) const terminal = ref<HTMLElement | null>(null)
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import FileNode from './FileNode.vue' import FileNode from '../FileNode.vue'
import sessionStore from '../store/session' import sessionStore from '../../store/session'
</script> </script>
<template> <template>
@@ -0,0 +1,108 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useToast } from 'vue-toastification'
import { logout } from '../../utils/auth'
import { bugReportUrl, surveyUrl } from '../../config'
import { reset } from '../../store/session'
import userProfileStore, {
loadUserProfile,
resetUserProfile,
} from '../../store/userProfile'
const router = useRouter()
const toast = useToast()
const handleLogout = async () => {
try {
await logout()
resetUserProfile()
reset()
router.push({ name: 'login' })
} catch (err) {
toast.error('登出失敗')
console.error(err)
}
}
onMounted(async () => {
try {
await loadUserProfile()
} catch (err) {
toast.error('無法讀取使用者資料')
console.error(err)
}
})
</script>
<template>
<!-- <button id="warning" class="flex items-center h-5 w-5">
<font-awesome-icon
:icon="['fas', 'triangle-exclamation']"
class="text-text-primary h-full w-full"
/>
</button>
<button id="setting" class="flex items-center h-5 w-5">
<font-awesome-icon
:icon="['fas', 'gear']"
class="text-text-primary h-full w-full"
/>
</button>
<button id="fullscreen" class="flex items-center h-5 w-5">
<font-awesome-icon
:icon="['fas', 'expand']"
class="text-text-primary h-full w-full"
/>
</button> -->
<p
id="UsernameText"
class="text-text inline-block whitespace-nowrap px-1.5"
style="font-size: 2vh"
>
{{ userProfileStore.username }}
</p>
<a
title="Survey"
:href="surveyUrl"
target="_blank"
class="md:h-5 md:w-5 px-1.5 w-auto"
>
<font-awesome-icon
:icon="['fas', 'file-invoice']"
class="text-text-primary inline"
/>
<span class="text-text sm:hidden px-2">Survey</span>
</a>
<RouterLink
title="LeaderBoard"
to="/leaderboard"
class="md:h-5 md:w-5 px-1.5 w-auto"
>
<font-awesome-icon :icon="['fas', 'trophy']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Leader Board</span>
</RouterLink>
<RouterLink title="Map" to="/map" class="md:h-5 md:w-5 px-1.5 w-auto">
<font-awesome-icon :icon="['fas', 'map']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Map</span>
</RouterLink>
<a
title="Bug Report"
:href="bugReportUrl"
target="_blank"
class="md:h-5 md:w-5 px-1.5 w-auto"
>
<font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" />
<span class="text-text sm:hidden px-2">Bug Report</span>
</a>
<button
title="Sign Out"
@click="handleLogout"
class="md:h-5 md:w-5 px-1.5 w-auto"
>
<font-awesome-icon
:icon="['fas', 'arrow-right-from-bracket']"
class="text-text-primary"
/>
<span class="text-text sm:hidden px-2">Sign Out</span>
</button>
</template>
+66
View File
@@ -0,0 +1,66 @@
<script setup lang="ts">
import { defineProps, ref } from 'vue'
defineProps({
title: {
type: String,
required: false,
},
headerComponent: {
type: Object,
required: false,
},
})
const menuOpen = ref(false)
const windowWidth = window.innerWidth < 768
const toggleMenu = () => {
menuOpen.value = !menuOpen.value
}
</script>
<template>
<div
class="w-full top-0 px-5 fixed flex flex-row flex-wrap bg-bg-secondary justify-between items-center sm:justify-between"
>
<div class="flex flex-row items-center gap-3" :class="{ hidden: menuOpen }">
<img src="../../img/icon_totem.svg" class="h-8 justify-self-start" />
<RouterLink
to="/"
id="GameTitle"
class="text-text-primary inline-block font-bold whitespace-nowrap pt-1 transition ease-in-out hover:scale-110 duration-300"
style="font-size: 2vh"
>
Linux Odyssey
</RouterLink>
<p
id="QuestTitle"
class="text-text inline-block font-bold whitespace-nowrap"
style="font-size: 2vh"
>
{{ title }}
</p>
</div>
<div
class="w-full flex flex-col items-center justify-end sm:w-auto sm:block sm:ml-6"
:class="{ hidden: !menuOpen }"
>
<component :is="headerComponent" />
</div>
<div
v-if="windowWidth"
:class="{ 'w-full flex justify-end pb-3': menuOpen }"
>
<button
type="button"
class="flex items-center h-5 w-5 rounded-md sm:hidden"
aria-controls="mobile-menu"
aria-expanded="false"
@click="toggleMenu"
>
<font-awesome-icon
:icon="['fas', 'bars']"
class="text-text-primary h-full w-full"
/>
</button>
</div>
</div>
</template>
@@ -0,0 +1,62 @@
<script setup lang="ts">
import { bugReportUrl } from '../../config'
const scrollToSection = (sectionId: string) => {
const section = document.getElementById(sectionId)
if (section) {
const container = document.querySelector('.overflow-y-auto') as HTMLElement // Replace '.overflow-y-auto' with the appropriate class or selector for your container
if (container) {
container.scrollTo({
top: section.offsetTop - container.offsetTop,
behavior: 'smooth', // Add smooth scrolling behavior if desired
})
}
}
}
</script>
<template>
<button
id="Intro"
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
@click="scrollToSection('intro')"
style="font-size: 2vh"
>
前言
</button>
<button
id="Feature"
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
@click="scrollToSection('feature')"
style="font-size: 2vh"
>
特色</button
><button
id="Info"
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
@click="scrollToSection('about')"
style="font-size: 2vh"
>
關於
</button>
<button
id="Contact"
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
@click="scrollToSection('contact')"
style="font-size: 2vh"
>
聯絡我們
</button>
<RouterLink
title="Sign In"
id="SignIn"
to="/register"
class="text-text inline-block font-bold whitespace-nowrap pt-1 px-2 hover:text-text-primary"
style="font-size: 2vh"
>
登入
</RouterLink>
<a title="Bug Report" :href="bugReportUrl" target="_blank" class="h-5 w-5">
<font-awesome-icon :icon="['fas', 'bug']" class="text-text-primary" />
</a>
</template>
+15 -11
View File
@@ -2,14 +2,15 @@
import { computed, onMounted } from 'vue' import { computed, onMounted } from 'vue'
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
import sessionStore, { init } from '../store/session' import sessionStore, { init } from '../store/session'
import GameHeaderPart from '../components/GameHeaderPart.vue' import HeaderPart from '../components/header/HeaderPart.vue'
import GameHeaderComponents from '../components/header/GameHeaderComponents.vue'
// import CommandlistPart from '../components/CommandlistPart.vue' // import CommandlistPart from '../components/CommandlistPart.vue'
import HintPart from '../components/HintPart.vue' import HintPart from '../components/game/HintPart.vue'
import QuestPart from '../components/QuestPart.vue' import QuestPart from '../components/game/QuestPart.vue'
import TerminalPart from '../components/TerminalPart.vue' import TerminalPart from '../components/game/TerminalPart.vue'
import VisualizationPart from '../components/VisualizationPart.vue' import VisualizationPart from '../components/game/VisualizationPart.vue'
import ControlPalette from '../components/ControlPalette.vue' import ControlPalette from '../components/game/ControlPalette.vue'
import CompleteModal from '../components/CompleteModal.vue' import CompleteModal from '../components/game/CompleteModal.vue'
import { LoadQuestError, LoadSessionError } from '../utils/errors' import { LoadQuestError, LoadSessionError } from '../utils/errors'
const completed = computed(() => { const completed = computed(() => {
@@ -45,8 +46,11 @@ onMounted(async () => {
<template> <template>
<!-- game header --> <!-- game header -->
<div class="h-[6vh] w-full"> <div class="w-full">
<GameHeaderPart :title="sessionStore.quest?.title" /> <HeaderPart
:title="sessionStore.quest?.title"
:headerComponent="GameHeaderComponents"
/>
</div> </div>
<!-- current status indicator --> <!-- current status indicator -->
<input <input
@@ -55,7 +59,7 @@ onMounted(async () => {
:value="sessionStore.session.status" :value="sessionStore.session.status"
/> />
<!-- main --> <!-- main -->
<div id="main" class="h-[94vh] w-full flex p-3 space-x-3"> <div id="main" class="h-full pt-10 w-full flex p-3 space-x-3">
<!-- Topic and Command List --> <!-- Topic and Command List -->
<div class="bg-bg-secondary h-full w-1/4 rounded-lg"> <div class="bg-bg-secondary h-full w-1/4 rounded-lg">
<section id="quest" class="h-full p-3 overflow-auto"> <section id="quest" class="h-full p-3 overflow-auto">
@@ -67,7 +71,7 @@ onMounted(async () => {
</section> --> </section> -->
</div> </div>
<!-- Terminal and Hint --> <!-- Terminal and Hint -->
<div class="bg-bg h-full w-1/2 rounded-lg"> <div class="bg-bg h-full rounded-lg w-1/2">
<section id="hint" class="h-3/5"> <section id="hint" class="h-3/5">
<HintPart /> <HintPart />
</section> </section>
+27 -101
View File
@@ -1,97 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import ContactButton from '../components/ContactButton.vue' import ContactButton from '../components/ContactButton.vue'
import DynamicBackground from '../components/DynamicBackground.vue' import DynamicBackground from '../components/DynamicBackground.vue'
import { bugReportUrl, facebookUrl, githubUrl } from '../config' import LandingHeaderComponents from '../components/header/LandingHeaderComponents.vue'
import HeaderPart from '../components/header/HeaderPart.vue'
const scrollToSection = (sectionId: string) => { import { facebookUrl, githubUrl } from '../config'
const section = document.getElementById(sectionId)
if (section) {
const container = document.querySelector('.overflow-y-auto') // Replace '.overflow-y-auto' with the appropriate class or selector for your container
if (container) {
container.scrollTo({
top: section.offsetTop,
behavior: 'smooth', // Add smooth scrolling behavior if desired
})
}
}
}
</script> </script>
<template> <template>
<div class="w-screen h-screen bg-scroll bg-bg"> <div class="w-screen h-screen bg-scroll bg-bg">
<DynamicBackground class="w-full h-full" /> <DynamicBackground class="w-full h-full" />
<div class="h-screen w-screen absolute top-0 left-0"> <div class="h-screen w-screen absolute top-0 left-0">
<!-- game header --> <!-- game header -->
<div <HeaderPart :headerComponent="LandingHeaderComponents" class="z-50" />
class="w-full h-[6vh] px-5 flex flex-row items-center justify-between bg-bg-secondary"
>
<div class="flex flex-row items-center gap-3">
<img src="../img/icon_totem.svg" class="h-8 justify-self-start" />
<button
id="GameTitle"
class="text-text-primary inline-block font-bold whitespace-nowrap pt-1"
style="font-size: 2vh"
>
Linux Odyssey
</button>
</div>
<div class="flex flex-row items-center gap-3">
<button
id="Intro"
class="text-text inline-block font-bold whitespace-nowrap pt-1"
@click="scrollToSection('intro')"
style="font-size: 2vh"
>
Intro
</button>
<button
id="Feature"
class="text-text inline-block font-bold whitespace-nowrap pt-1"
@click="scrollToSection('feature')"
style="font-size: 2vh"
>
Feature</button
><button
id="Info"
class="text-text inline-block font-bold whitespace-nowrap pt-1"
@click="scrollToSection('about')"
style="font-size: 2vh"
>
About
</button>
<button
id="Contact"
class="text-text inline-block font-bold whitespace-nowrap pt-1"
@click="scrollToSection('contact')"
style="font-size: 2vh"
>
Contact Us
</button>
<RouterLink
title="Sign In"
id="SignIn"
to="/register"
class="text-text inline-block font-bold whitespace-nowrap pt-1"
style="font-size: 2vh"
>
Sign In
</RouterLink>
<a
title="Bug Report"
:href="bugReportUrl"
target="_blank"
class="h-5 w-5"
>
<font-awesome-icon
:icon="['fas', 'bug']"
class="text-text-primary h-full w-full"
/>
</a>
</div>
</div>
<!-- main content --> <!-- main content -->
<main class="w-full h-[94vh] overflow-y-auto"> <main class="w-full h-full overflow-y-auto">
<div class="w-full flex flex-col items-center"> <div class="w-full flex flex-col items-center">
<div <div
class="flex flex-col md:flex-row mt-10 justify-around gap-5 items-center my-10" class="flex flex-col md:flex-row mt-10 justify-around gap-5 items-center my-10"
@@ -104,7 +26,6 @@ const scrollToSection = (sectionId: string) => {
Odyssey Odyssey
</h1> </h1>
</div> </div>
<!-- intro --> <!-- intro -->
<div class="w-full md:w-2/3 px-5"> <div class="w-full md:w-2/3 px-5">
<section <section
@@ -228,40 +149,43 @@ const scrollToSection = (sectionId: string) => {
鈦坦敏捷開發特別獎 第二名 鈦坦敏捷開發特別獎 第二名
</h1> </h1>
</div> </div>
<div class="container mx-auto">
<!-- <h1 <div
class="text-text-primary p-5 font-extrabold font-mono col-span-3 gap-3" class="justify-items-center grid grid-cols-1 sm:grid-cols-3 gap-5"
style="font-size: 3.5vh" >
<h1
class="text-text-primary text-3xl font-extrabold font-mono sm:col-span-3 gap-6"
> >
玩家感想 玩家感想
<!--可以做成翻頁卡牌一次一個-->
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">"很好玩很像益智遊戲"</h1>
"很好玩很像益智遊戲" <h1 class="text-xl text-center">
</h1>
<h1 class="text-text p-3" style="font-size: 2.5vh">
"我從來不知道自由軟體的存在,謝謝你們。" "我從來不知道自由軟體的存在,謝謝你們。"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"還蠻好玩的,讓程式變好玩" "還蠻好玩的,讓程式變好玩"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"以前不喜歡電腦課現在覺得喜歡一點點" "以前不喜歡電腦課現在覺得喜歡一點點"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"程式真的對新手很友善,讓我學到了很多東西" "程式真的對新手很友善,讓我學到了很多東西"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"感覺做得很好很簡明易懂關卡設計很用心" "感覺做得很好很簡明易懂關卡設計很用心"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"這個體驗我覺得非常有趣,可以體驗到沒辦法體驗的程式,學長也都熱心指導,非常感謝學長的用心的講解,希望以後還可以再體驗這種活動" "這個體驗我覺得非常有趣,可以體驗到沒辦法體驗的程式,學長也都熱心指導,非常感謝學長的用心的講解,希望以後還可以再體驗這種活動"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"以前我覺得寫程式很難不過現在覺得很有趣" "以前我覺得寫程式很難不過現在覺得很有趣"
</h1> </h1>
<h1 class="text-text p-3" style="font-size: 2.5vh"> <h1 class="text-xl text-center">
"以前覺得寫程式是我生活中碰不到而且很難的項目。但通過這堂課之後,覺得寫程式不再那麼難以親近" "以前覺得寫程式是我生活中碰不到而且很難的項目。但通過這堂課之後,覺得寫程式不再那麼難以親近"
</h1> --> </h1>
</div>
</div>
</section> </section>
</div> </div>
<section <section
@@ -271,7 +195,9 @@ const scrollToSection = (sectionId: string) => {
<h1 class="text-text-primary font-extrabold font-mono text-3xl"> <h1 class="text-text-primary font-extrabold font-mono text-3xl">
聯絡我們 聯絡我們
</h1> </h1>
<div class="flex flex-row items-center justify-around mt-5 gap-5"> <div
class="flex flex-row items-center justify-around mt-5 gap-5 mb-5"
>
<ContactButton <ContactButton
:url="facebookUrl" :url="facebookUrl"
:icons="['fab', 'facebook']" :icons="['fab', 'facebook']"
+4 -3
View File
@@ -2,7 +2,8 @@
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useToast } from 'vue-toastification' import { useToast } from 'vue-toastification'
import DynamicBackground from '../components/DynamicBackground.vue' import DynamicBackground from '../components/DynamicBackground.vue'
import GameHeaderPart from '../components/GameHeaderPart.vue' import HeaderPart from '../components/header/HeaderPart.vue'
import GameHeaderComponents from '../components/header/GameHeaderComponents.vue'
import api from '../utils/api' import api from '../utils/api'
const leaderboard = ref< const leaderboard = ref<
@@ -35,8 +36,8 @@ onMounted(async () => {
<div <div
class="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center" class="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center"
> >
<div class="h-[6vh] w-full"> <div class="w-full">
<GameHeaderPart title="排行榜" /> <HeaderPart title="排行榜" :headerComponent="GameHeaderComponents" />
</div> </div>
<div class="w-fit h-[94vh] m-3"> <div class="w-fit h-[94vh] m-3">
<div <div
+4 -2
View File
@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
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 { import {
TooManyRequestsError, TooManyRequestsError,
@@ -45,10 +46,11 @@ const handleLogin = async ({
<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="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center" class="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center"
> >
<HeaderPart />
<div class="w-fit"> <div class="w-fit">
<AuthForm @onSubmit="handleLogin" type="login" /> <AuthForm @onSubmit="handleLogin" type="login" />
</div> </div>
+9 -4
View File
@@ -1,13 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import QuestMap from '../components/QuestMap.vue' import QuestMap from '../components/QuestMap.vue'
import GameHeaderPart from '../components/GameHeaderPart.vue' import HeaderPart from '../components/header/HeaderPart.vue'
import GameHeaderComponents from '../components/header/GameHeaderComponents.vue'
</script> </script>
<template> <template>
<div class="h-[6vh] w-full"> <div class="w-fit">
<GameHeaderPart title="關卡地圖" /> <HeaderPart
title="關卡地圖"
:headerComponent="GameHeaderComponents"
class="z-50"
/>
</div> </div>
<div class="flex flex-col justify-center items-center w-full h-[94vh]"> <div class="flex flex-col justify-center items-center w-full h-full pt-5">
<QuestMap /> <QuestMap />
</div> </div>
</template> </template>
+5 -4
View File
@@ -3,8 +3,8 @@ import validator from 'validator'
import { isValidUsername } from '@linux-odyssey/utils' import { isValidUsername } from '@linux-odyssey/utils'
import { passwordPolicy } from '@linux-odyssey/constants' import { passwordPolicy } from '@linux-odyssey/constants'
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 { checkUsername, register } from '../utils/auth' import { checkUsername, register } from '../utils/auth'
import { import {
UnauthorizedError, UnauthorizedError,
@@ -89,11 +89,12 @@ async function check({
<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"
> >
<div class="w-fit"> <HeaderPart />
<div class="w-fit mt-8">
<AuthForm <AuthForm
@onSubmit="handleRegister" @onSubmit="handleRegister"
@onChange="check" @onChange="check"
-1
View File
@@ -8,5 +8,4 @@ mv world.txt wow.txt
ls ls
mv notes docs mv notes docs
ls ls
echo hint
mv docs/hello.txt hi.txt mv docs/hello.txt hi.txt
+4 -4
View File
@@ -5,7 +5,7 @@ export default function checkLoginUI() {
describe('example helloworld app', () => { describe('example helloworld app', () => {
describe('Login tests', () => { describe('Login tests', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/') cy.visit('/register')
}) })
it('Check Login Page Elements-Register', () => { it('Check Login Page Elements-Register', () => {
checkLoginUI() checkLoginUI()
@@ -83,11 +83,11 @@ describe('example helloworld app', () => {
cy.get('#UsernameText') cy.get('#UsernameText')
.should('contain', Cypress.env('defaultAccount')) .should('contain', Cypress.env('defaultAccount'))
.and('be.visible') .and('be.visible')
cy.findByRole('link', { name: 'Survey' }).should('be.visible')
cy.findByRole('link', { name: 'LeaderBoard' }).should('be.visible')
cy.findByRole('link', { name: 'Map' }).should('be.visible')
cy.findByRole('link', { name: 'Bug Report' }).should('be.visible') cy.findByRole('link', { name: 'Bug Report' }).should('be.visible')
cy.findByRole('button', { name: 'Sign Out' }).should('be.visible') cy.findByRole('button', { name: 'Sign Out' }).should('be.visible')
cy.findByRole('button', { name: 'Map' }).should('be.visible')
cy.findByRole('button', { name: 'LeaderBoard' }).should('be.visible')
cy.findByRole('link', { name: 'Survey' }).should('be.visible')
}) })
it('Check QuestInfo', () => { it('Check QuestInfo', () => {
cy.get('#topic').should('contain', title) cy.get('#topic').should('contain', title)
+5 -5
View File
@@ -8,7 +8,7 @@ declare global {
namespace Cypress { namespace Cypress {
interface Chainable { interface Chainable {
LoginWithPassword(username: string, password: string): Chainable<string> LoginWithPassword(username: string, password: string): Chainable<string>
PrepareForGame(): Chainable<void> PrepareForGame(questId: string): Chainable<string>
InitTerminal(): Chainable<void> InitTerminal(): Chainable<void>
typeInCommand(command: string): Chainable<string> typeInCommand(command: string): Chainable<string>
getQuestInfo(id: string): Chainable<JQuery<HTMLParagraphElement>> getQuestInfo(id: string): Chainable<JQuery<HTMLParagraphElement>>
@@ -38,8 +38,8 @@ Cypress.Commands.add('LoginWithPassword', (username, password) => {
cy.get('#password').type(password) cy.get('#password').type(password)
cy.get('#LogInOrSignUp').click() cy.get('#LogInOrSignUp').click()
}) })
Cypress.Commands.add('PrepareForGame', (questId) => { Cypress.Commands.add('PrepareForGame', (questId: string) => {
cy.visit('/') cy.visit('/login')
// make sure the login page is loaded // make sure the login page is loaded
cy.url().should('satisfy', (elements: string) => { cy.url().should('satisfy', (elements: string) => {
const text = elements const text = elements
@@ -143,9 +143,9 @@ Cypress.Commands.add('CompleteStageWithCommands', (stagename) => {
}) })
Cypress.Commands.add('CheckTextElement', (id, chText, enText) => { Cypress.Commands.add('CheckTextElement', (id, chText, enText) => {
if (Cypress.env('isCHVersion')) { if (Cypress.env('isCHVersion')) {
cy.get(id, { timeout: 50000 }).should('contain', chText).and('be.visible') cy.get(id, { timeout: 7000 }).should('contain', chText).and('be.visible')
} else { } else {
cy.get(id, { timeout: 50000 }).should('contain', enText).and('be.visible') cy.get(id, { timeout: 7000 }).should('contain', enText).and('be.visible')
} }
}) })
Cypress.Commands.add('CheckPlaceholder', (id, chText, enText) => { Cypress.Commands.add('CheckPlaceholder', (id, chText, enText) => {
+3 -3
View File
@@ -7717,9 +7717,9 @@ tar-stream@^2.0.0:
readable-stream "^3.1.1" readable-stream "^3.1.1"
tar@^6.1.11: tar@^6.1.11:
version "6.2.0" version "6.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
dependencies: dependencies:
chownr "^2.0.0" chownr "^2.0.0"
fs-minipass "^2.0.0" fs-minipass "^2.0.0"