update: mobile navbar
This commit is contained in:
+20
-11
@@ -24,7 +24,7 @@ function logout() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav>
|
<nav>
|
||||||
<div class="ts-container navbar-container">
|
<div class="ts-container navbar-container" v-if="!$isMobile">
|
||||||
<div class="ts-wrap">
|
<div class="ts-wrap">
|
||||||
<RouterLink class="ts-header is-brand" to="/">網路攻防實習</RouterLink>
|
<RouterLink class="ts-header is-brand" to="/">網路攻防實習</RouterLink>
|
||||||
<div class="ts-tab is-tall">
|
<div class="ts-tab is-tall">
|
||||||
@@ -43,6 +43,25 @@ function logout() {
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ts-container" v-else>
|
||||||
|
<div class="ts-wrap navbar-container">
|
||||||
|
<RouterLink class="ts-header is-brand has-top-padded has-bottom-padded" to="/">網路攻防實習</RouterLink>
|
||||||
|
<div class="actions ts-wrap">
|
||||||
|
<template v-if="isLoggedIn">
|
||||||
|
<span class="username">{{ username }}</span>
|
||||||
|
<RouterLink class="ts-button is-icon is-outlined" to="/profile"><span class="ts-icon is-user-icon"></span></RouterLink>
|
||||||
|
<div class="ts-button" @click="logout">登出</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<RouterLink class="ts-button" to="/login">登入</RouterLink>
|
||||||
|
<RouterLink class="ts-button" to="/register">註冊</RouterLink>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ts-tab is-tall is-center-aligned">
|
||||||
|
<RouterLink class="item" :to="route.path" :class="{'is-active': route.path == $route.path}" v-for="route in $router.options.routes.filter(route => route.meta.showInNav)">{{ route.meta.navName }}</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -66,14 +85,4 @@ nav {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.navbar-container {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
const mobileMediaQuery = 'screen and (max-width: 768px)';
|
||||||
|
const matchMedia = window.matchMedia(mobileMediaQuery);
|
||||||
|
|
||||||
|
const isMobile = reactive(matchMedia.matches);
|
||||||
|
|
||||||
|
matchMedia.addEventListener('change', (event) => {
|
||||||
|
isMobile = event.matches;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const install = (app) => {
|
||||||
|
app.config.globalProperties.$isMobile = isMobile;
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import router from './router';
|
|||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import { install as installRecaptcha } from "vue3-recaptcha-v2";
|
import { install as installRecaptcha } from "vue3-recaptcha-v2";
|
||||||
import { install as installDarkMode } from './lib/darkMode';
|
import { install as installDarkMode } from './lib/darkMode';
|
||||||
|
import { install as installIsMobile } from './lib/isMobile';
|
||||||
|
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
@@ -12,6 +13,7 @@ const app = createApp(App);
|
|||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(installDarkMode);
|
app.use(installDarkMode);
|
||||||
|
app.use(installIsMobile);
|
||||||
app.use(installRecaptcha, {
|
app.use(installRecaptcha, {
|
||||||
sitekey: import.meta.env.VITE_RECAPTCHA_SITEKEY
|
sitekey: import.meta.env.VITE_RECAPTCHA_SITEKEY
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const generateMotto = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="ts-app-center">
|
<div class="ts-app-center">
|
||||||
<div>
|
<div class="ts-content is-horizontally-fitted">
|
||||||
<div class="ts-box ts-content is-center-aligned">
|
<div class="ts-box ts-content is-center-aligned">
|
||||||
<div class="ts-header is-large is-center-aligned">每日金句生成器</div>
|
<div class="ts-header is-large is-center-aligned">每日金句生成器</div>
|
||||||
<div class="ts-header is-secondary is-center-aligned">Powered By Cloudflare Workers AI</div>
|
<div class="ts-header is-secondary is-center-aligned">Powered By Cloudflare Workers AI</div>
|
||||||
@@ -53,7 +53,7 @@ const generateMotto = async () => {
|
|||||||
<button class="ts-button" @click="generateMotto" :disabled="!captchaVerified">生成</button>
|
<button class="ts-button" @click="generateMotto" :disabled="!captchaVerified">生成</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ts-content is-center-aligned">
|
<div class="ts-content is-center-aligned">
|
||||||
<p class="ts-text">每日金句:</p>
|
<p class="ts-text" v-if="mottoLoading || motto">每日金句:</p>
|
||||||
<div class="ts-loading" v-if="mottoLoading"></div>
|
<div class="ts-loading" v-if="mottoLoading"></div>
|
||||||
<div class="ts-quote" v-if="motto">
|
<div class="ts-quote" v-if="motto">
|
||||||
<p class="ts-text">{{ motto }}</p>
|
<p class="ts-text">{{ motto }}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user