mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-05 19:20:12 +08:00
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
This commit is contained in:
17 files changed
+340
-180
No files matched your search
+1
-1
@@ -2,6 +2,6 @@
|
||||
<font-awesome-icon :icon="['fas', 'list']" class="text-text-primary p-1" />
|
||||
<h1 id="CommandBook" class="inline text-text-primary font-xl">指令之書</h1>
|
||||
<div id="cheatsheets">
|
||||
<p class="text-text-secondary">--指令列表--</p>
|
||||
<p class="text-text-secondary">-- --指令列表-- --</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -4,7 +4,7 @@ import { useToast } from 'vue-toastification'
|
||||
import { ref } from 'vue'
|
||||
import { Vue3Lottie } from 'vue3-lottie'
|
||||
// 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 router = useRouter()
|
||||
@@ -26,7 +26,6 @@ const backtoMap = async () => {
|
||||
try {
|
||||
router.push({ name: 'map' })
|
||||
} catch (err) {
|
||||
// useToast().error('Failed to load map')
|
||||
toast.error('無法讀取地圖')
|
||||
console.error(err)
|
||||
}
|
||||
@@ -60,17 +59,6 @@ setTimeout(() => {
|
||||
<p class="text-base text-text text-center">
|
||||
接下來回到地圖,迎接新的挑戰吧!
|
||||
</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
|
||||
id="BacktoMap"
|
||||
target="_blank"
|
||||
+13
-11
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { createSession } from '../store/session'
|
||||
import { surveyUrl } from '../config'
|
||||
import { createSession } from '../../store/session'
|
||||
import { surveyUrl } from '../../config'
|
||||
|
||||
const router = useRouter()
|
||||
const reset = async () => {
|
||||
@@ -20,29 +20,31 @@ const continuePlay = async () => {
|
||||
</script>
|
||||
|
||||
<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">
|
||||
<a title="Survey" :href="surveyUrl" target="_blank" class="h-5 w-5">
|
||||
<font-awesome-icon
|
||||
: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>
|
||||
</button>
|
||||
<button disabled id="solution" class="bg-bg-disabled rounded-lg p-2">
|
||||
<font-awesome-icon
|
||||
: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 id="reset" class="bg-bg-secondary rounded-lg p-2" @click="reset">
|
||||
<font-awesome-icon
|
||||
: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
|
||||
id="continue"
|
||||
@@ -51,9 +53,9 @@ const continuePlay = async () => {
|
||||
>
|
||||
<font-awesome-icon
|
||||
: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>
|
||||
</section>
|
||||
</template>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import sessionStore from '../store/session'
|
||||
import MarkdownText from './MarkdownText.vue'
|
||||
import sessionStore from '../../store/session'
|
||||
import MarkdownText from '../MarkdownText.vue'
|
||||
|
||||
const current = ref(-1)
|
||||
watch(
|
||||
@@ -27,16 +27,12 @@ const right = () => {
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<!-- Hint Header -->
|
||||
<div class="flex items-center p-2 h-10">
|
||||
<font-awesome-icon
|
||||
:icon="['far', 'lightbulb']"
|
||||
class="text-yellow-200 p-2 content-center"
|
||||
/>
|
||||
<h1 class="inline text-text w-1/2 font-xl p-2 m-1">
|
||||
<!-- Hint -->
|
||||
提示
|
||||
</h1>
|
||||
<h1 class="inline text-text w-1/2 font-xl p-2 m-1">提示</h1>
|
||||
<div v-if="current !== -1" class="flex w-full justify-end items-end">
|
||||
<button
|
||||
class="p-2 m-1 w-1/8"
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import MarkdownText from './MarkdownText.vue'
|
||||
import sessionStore from '../store/session'
|
||||
import { Task } from '../types'
|
||||
import MarkdownText from '../MarkdownText.vue'
|
||||
import sessionStore from '../../store/session'
|
||||
import { Task } from '../../types'
|
||||
|
||||
const tasks = computed(() => {
|
||||
return sessionStore.session.tasks.map((task: Task) => {
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useTerminal } from '../store/session'
|
||||
import { useTerminal } from '../../store/session'
|
||||
|
||||
const terminal = ref<HTMLElement | null>(null)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import FileNode from './FileNode.vue'
|
||||
import sessionStore from '../store/session'
|
||||
import FileNode from '../FileNode.vue'
|
||||
import sessionStore from '../../store/session'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
File renamed without changes.
@@ -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>
|
||||
@@ -0,0 +1,65 @@
|
||||
<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="/"
|
||||
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
@@ -2,14 +2,15 @@
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useToast } from 'vue-toastification'
|
||||
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 HintPart from '../components/HintPart.vue'
|
||||
import QuestPart from '../components/QuestPart.vue'
|
||||
import TerminalPart from '../components/TerminalPart.vue'
|
||||
import VisualizationPart from '../components/VisualizationPart.vue'
|
||||
import ControlPalette from '../components/ControlPalette.vue'
|
||||
import CompleteModal from '../components/CompleteModal.vue'
|
||||
import HintPart from '../components/game/HintPart.vue'
|
||||
import QuestPart from '../components/game/QuestPart.vue'
|
||||
import TerminalPart from '../components/game/TerminalPart.vue'
|
||||
import VisualizationPart from '../components/game/VisualizationPart.vue'
|
||||
import ControlPalette from '../components/game/ControlPalette.vue'
|
||||
import CompleteModal from '../components/game/CompleteModal.vue'
|
||||
import { LoadQuestError, LoadSessionError } from '../utils/errors'
|
||||
|
||||
const completed = computed(() => {
|
||||
@@ -45,8 +46,11 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<!-- game header -->
|
||||
<div class="h-[6vh] w-full">
|
||||
<GameHeaderPart :title="sessionStore.quest?.title" />
|
||||
<div class="w-full">
|
||||
<HeaderPart
|
||||
:title="sessionStore.quest?.title"
|
||||
:headerComponent="GameHeaderComponents"
|
||||
/>
|
||||
</div>
|
||||
<!-- current status indicator -->
|
||||
<input
|
||||
@@ -55,7 +59,7 @@ onMounted(async () => {
|
||||
:value="sessionStore.session.status"
|
||||
/>
|
||||
<!-- 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 -->
|
||||
<div class="bg-bg-secondary h-full w-1/4 rounded-lg">
|
||||
<section id="quest" class="h-full p-3 overflow-auto">
|
||||
@@ -67,7 +71,7 @@ onMounted(async () => {
|
||||
</section> -->
|
||||
</div>
|
||||
<!-- 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">
|
||||
<HintPart />
|
||||
</section>
|
||||
|
||||
+45
-119
@@ -1,97 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import ContactButton from '../components/ContactButton.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) => {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
import { facebookUrl, githubUrl } from '../config'
|
||||
</script>
|
||||
<template>
|
||||
<div class="w-screen h-screen bg-scroll bg-bg">
|
||||
<DynamicBackground class="w-full h-full" />
|
||||
<div class="h-screen w-screen absolute top-0 left-0">
|
||||
<!-- game header -->
|
||||
<div
|
||||
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>
|
||||
|
||||
<HeaderPart :headerComponent="LandingHeaderComponents" class="z-50" />
|
||||
<!-- 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="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
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- intro -->
|
||||
<div class="w-full md:w-2/3 px-5">
|
||||
<section
|
||||
@@ -228,40 +149,43 @@ const scrollToSection = (sectionId: string) => {
|
||||
鈦坦敏捷開發特別獎 第二名
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- <h1
|
||||
class="text-text-primary p-5 font-extrabold font-mono col-span-3 gap-3"
|
||||
style="font-size: 3.5vh"
|
||||
>
|
||||
玩家感想
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"很好玩很像益智遊戲"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"我從來不知道自由軟體的存在,謝謝你們。"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"還蠻好玩的,讓程式變好玩"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"以前不喜歡電腦課現在覺得喜歡一點點"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"程式真的對新手很友善,讓我學到了很多東西"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"感覺做得很好很簡明易懂關卡設計很用心"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"這個體驗我覺得非常有趣,可以體驗到沒辦法體驗的程式,學長也都熱心指導,非常感謝學長的用心的講解,希望以後還可以再體驗這種活動"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"以前我覺得寫程式很難不過現在覺得很有趣"
|
||||
</h1>
|
||||
<h1 class="text-text p-3" style="font-size: 2.5vh">
|
||||
"以前覺得寫程式是我生活中碰不到而且很難的項目。但通過這堂課之後,覺得寫程式不再那麼難以親近"
|
||||
</h1> -->
|
||||
<div class="container mx-auto">
|
||||
<div
|
||||
class="justify-items-center grid grid-cols-1 sm:grid-cols-3 gap-5"
|
||||
>
|
||||
<h1
|
||||
class="text-text-primary text-3xl font-extrabold font-mono sm:col-span-3 gap-6"
|
||||
>
|
||||
玩家感想
|
||||
<!--可以做成翻頁卡牌一次一個-->
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">"很好玩很像益智遊戲"</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"我從來不知道自由軟體的存在,謝謝你們。"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"還蠻好玩的,讓程式變好玩"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"以前不喜歡電腦課現在覺得喜歡一點點"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"程式真的對新手很友善,讓我學到了很多東西"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"感覺做得很好很簡明易懂關卡設計很用心"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"這個體驗我覺得非常有趣,可以體驗到沒辦法體驗的程式,學長也都熱心指導,非常感謝學長的用心的講解,希望以後還可以再體驗這種活動"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"以前我覺得寫程式很難不過現在覺得很有趣"
|
||||
</h1>
|
||||
<h1 class="text-xl text-center">
|
||||
"以前覺得寫程式是我生活中碰不到而且很難的項目。但通過這堂課之後,覺得寫程式不再那麼難以親近"
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<section
|
||||
@@ -271,7 +195,9 @@ const scrollToSection = (sectionId: string) => {
|
||||
<h1 class="text-text-primary font-extrabold font-mono text-3xl">
|
||||
聯絡我們
|
||||
</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
|
||||
:url="facebookUrl"
|
||||
:icons="['fab', 'facebook']"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useToast } from 'vue-toastification'
|
||||
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'
|
||||
|
||||
const leaderboard = ref<
|
||||
@@ -35,8 +36,8 @@ onMounted(async () => {
|
||||
<div
|
||||
class="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center"
|
||||
>
|
||||
<div class="h-[6vh] w-full">
|
||||
<GameHeaderPart title="排行榜" />
|
||||
<div class="w-full">
|
||||
<HeaderPart title="排行榜" :headerComponent="GameHeaderComponents" />
|
||||
</div>
|
||||
<div class="w-fit h-[94vh] m-3">
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
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,
|
||||
@@ -45,10 +46,11 @@ const handleLogin = async ({
|
||||
|
||||
<template>
|
||||
<div class="w-screen h-screen">
|
||||
<Background class="w-full h-full" />
|
||||
<DynamicBackground class="w-full h-full" />
|
||||
<div
|
||||
class="w-screen h-screen absolute top-0 left-0 flex flex-wrap justify-center content-center"
|
||||
>
|
||||
<HeaderPart />
|
||||
<div class="w-fit">
|
||||
<AuthForm @onSubmit="handleLogin" type="login" />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
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>
|
||||
|
||||
<template>
|
||||
<div class="h-[6vh] w-full">
|
||||
<GameHeaderPart title="關卡地圖" />
|
||||
<div class="w-fit">
|
||||
<HeaderPart
|
||||
title="關卡地圖"
|
||||
:headerComponent="GameHeaderComponents"
|
||||
class="z-50"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center items-center w-full h-[94vh]">
|
||||
<QuestMap />
|
||||
|
||||
@@ -3,8 +3,8 @@ import validator from 'validator'
|
||||
import { isValidUsername } from '@linux-odyssey/utils'
|
||||
import { passwordPolicy } from '@linux-odyssey/constants'
|
||||
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 {
|
||||
UnauthorizedError,
|
||||
@@ -89,11 +89,12 @@ async function check({
|
||||
|
||||
<template>
|
||||
<div class="w-screen h-screen">
|
||||
<Background class="w-full h-full" />
|
||||
<DynamicBackground class="w-full h-full" />
|
||||
<div
|
||||
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
|
||||
@onSubmit="handleRegister"
|
||||
@onChange="check"
|
||||
|
||||
Reference in new issue
Block a user