merge: fix: fix ssr teleports and i18n #26
This commit is contained in:
parent
640f118185
commit
72a301bfee
|
@ -17,6 +17,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="app"><!--ssr-outlet--></div>
|
||||
<div id="teleported"><!--teleports--></div>
|
||||
<script type="module" src="/src/entry-client.ts"></script>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -13,6 +13,17 @@ const APP_PORT = 1007
|
|||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
// Inject teleports in template
|
||||
const injectTeleports = (
|
||||
html: string,
|
||||
teleports: {
|
||||
'#teleported': string
|
||||
}
|
||||
) => {
|
||||
// return html
|
||||
return html.replace('<!--teleports-->', teleports['#teleported'])
|
||||
}
|
||||
|
||||
;(async (hmrPort) => {
|
||||
const app = new Koa()
|
||||
|
||||
|
@ -32,9 +43,20 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|||
appType: 'custom',
|
||||
})
|
||||
|
||||
// 解析accept-language
|
||||
function parseAcceptLanguage(acceptLanguage: string) {
|
||||
const languages = acceptLanguage.split(',')
|
||||
const language = languages[0]
|
||||
const country = language.split('-')[1]
|
||||
return { language, country }
|
||||
}
|
||||
|
||||
app.use(koaConnect(vite.middlewares))
|
||||
|
||||
app.use(async (ctx) => {
|
||||
const { language, country } = parseAcceptLanguage(
|
||||
ctx.request.headers['accept-language'] as string
|
||||
)
|
||||
try {
|
||||
let template = fs.readFileSync(
|
||||
path.resolve(__dirname, 'index.html'),
|
||||
|
@ -45,9 +67,17 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|||
|
||||
const { render } = await vite.ssrLoadModule('/src/entry-server.ts')
|
||||
|
||||
const [renderedHtml, renderedPinia, renderedLinks] = await render(ctx, {})
|
||||
const [renderedHtml, renderedPinia, renderedLinks, renderedTeleports] =
|
||||
await render(
|
||||
ctx,
|
||||
{},
|
||||
{
|
||||
language,
|
||||
country,
|
||||
}
|
||||
)
|
||||
|
||||
const html = template
|
||||
const html = injectTeleports(template, renderedTeleports)
|
||||
.replace('<!--preload-links-->', renderedLinks)
|
||||
.replace('<!--ssr-outlet-->', renderedHtml)
|
||||
.replace('__pinia', renderedPinia)
|
||||
|
|
110
src/components/alert/Alert.vue
Normal file
110
src/components/alert/Alert.vue
Normal file
|
@ -0,0 +1,110 @@
|
|||
<script setup lang="ts">
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const { showAlert, alertMsg, isShowCancel } = storeToRefs(
|
||||
useKUNGalgameMessageStore()
|
||||
)
|
||||
|
||||
const handleClose = () => {
|
||||
showAlert.value = false
|
||||
useKUNGalgameMessageStore().handleClose()
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
showAlert.value = false
|
||||
useKUNGalgameMessageStore().handleConfirm()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="#teleported" :disabled="showAlert">
|
||||
<Transition name="alert">
|
||||
<div>
|
||||
<div v-if="showAlert" class="mask">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h3>{{ $t(`${alertMsg}`) }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<button v-if="isShowCancel" class="button" @click="handleClose">
|
||||
{{ $tm('ComponentAlert.cancel') }}
|
||||
</button>
|
||||
<button class="button" @click="handleConfirm">
|
||||
{{ $tm('ComponentAlert.confirm') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mask {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--kungalgame-mask-color-0);
|
||||
display: flex;
|
||||
transition: opacity 0.3s ease;
|
||||
color: var(--kungalgame-font-color-3);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 300px;
|
||||
margin: auto;
|
||||
padding: 20px 30px;
|
||||
background-color: var(--kungalgame-trans-white-2);
|
||||
border: 1px solid var(--kungalgame-blue-1);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 70px;
|
||||
height: 30px;
|
||||
color: var(--kungalgame-font-color-3);
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
&:nth-child(1) {
|
||||
background-color: var(--kungalgame-trans-blue-1);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
}
|
||||
&:nth-child(2) {
|
||||
margin-left: 98px;
|
||||
background-color: var(--kungalgame-trans-red-1);
|
||||
border: 1px solid var(--kungalgame-red-4);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
transition: 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-enter-from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.alert-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.alert-enter-from .container,
|
||||
.alert-leave-to .container {
|
||||
-webkit-transform: scale(1.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
</style>
|
152
src/components/alert/Info.vue
Normal file
152
src/components/alert/Info.vue
Normal file
|
@ -0,0 +1,152 @@
|
|||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import img from './loli'
|
||||
import 'animate.css'
|
||||
|
||||
const { showInfo, infoMsg } = storeToRefs(useKUNGalgameMessageStore())
|
||||
|
||||
const { loli, name } = img
|
||||
|
||||
const handleClose = () => {
|
||||
showInfo.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="#teleported" :disabled="showInfo">
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__fadeInUp animate__faster"
|
||||
leave-active-class="animate__animated animate__fadeOutDown animate__faster"
|
||||
>
|
||||
<div>
|
||||
<div class="container" v-if="showInfo">
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__swing"
|
||||
appear
|
||||
>
|
||||
<div class="lass">
|
||||
<span>{{ name }}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<div class="avatar">
|
||||
<img :src="loli" />
|
||||
</div>
|
||||
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__bounceInRight animate__faster"
|
||||
appear
|
||||
>
|
||||
<!-- A ha ha ha! You probably didn't expect that this was inspired by しゅがてん!-Sugarfull tempering- -->
|
||||
<div class="info">{{ `「 ${$t(`${infoMsg}`)} 」` }}</div>
|
||||
</Transition>
|
||||
|
||||
<div class="close" @click="handleClose">
|
||||
<Icon icon="line-md:close" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-height: 120px;
|
||||
width: 100%;
|
||||
color: var(--kungalgame-font-color-3);
|
||||
background-color: var(--kungalgame-trans-white-5);
|
||||
backdrop-filter: blur(2px);
|
||||
box-shadow: var(--shadow);
|
||||
border-top: 1px solid var(--kungalgame-blue-1);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.lass {
|
||||
padding: 5px;
|
||||
font-size: 20px;
|
||||
position: absolute;
|
||||
top: -41px;
|
||||
padding-left: 150px;
|
||||
border-bottom: none;
|
||||
/* This shadow can only be drawn like this */
|
||||
filter: drop-shadow(2px 4px 3px var(--kungalgame-trans-blue-4));
|
||||
|
||||
span {
|
||||
padding: 0 50px;
|
||||
text-align: center;
|
||||
background-color: var(--kungalgame-trans-white-2);
|
||||
font-size: 24px;
|
||||
/* Here, the shape of the character's name is clipped into a hexagon */
|
||||
clip-path: polygon(10% 0%, 90% 0%, 100% 50%, 90% 100%, 10% 100%, 0 50%);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
margin-left: 20px;
|
||||
|
||||
img {
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-top: 20px;
|
||||
margin-left: 150px;
|
||||
margin-right: 50px;
|
||||
font-size: 20px;
|
||||
color: var(--kungalgame-white);
|
||||
text-shadow: 0 1px var(--kungalgame-font-color-3),
|
||||
1px 0 var(--kungalgame-font-color-3), -1px 0 var(--kungalgame-font-color-3),
|
||||
0 -1px var(--kungalgame-font-color-3),
|
||||
1px 2px var(--kungalgame-font-color-3),
|
||||
1px 2px var(--kungalgame-font-color-3),
|
||||
1px 2px var(--kungalgame-font-color-3),
|
||||
1px 2px var(--kungalgame-font-color-3);
|
||||
}
|
||||
.close {
|
||||
font-size: 30px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: var(--kungalgame-font-color-1);
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.container {
|
||||
min-height: 77px;
|
||||
}
|
||||
|
||||
.lass {
|
||||
padding: 5px;
|
||||
font-size: 15px;
|
||||
padding-left: 20px;
|
||||
top: -33px;
|
||||
|
||||
span {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
margin-top: 10px;
|
||||
margin-right: 30px;
|
||||
margin-left: 77px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
img {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
307
src/components/capture/Capture.vue
Normal file
307
src/components/capture/Capture.vue
Normal file
|
@ -0,0 +1,307 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
// Import questions
|
||||
import { questionsEN, Question } from './questionsEN'
|
||||
import { questionsCN } from './questionsCN'
|
||||
|
||||
import Message from '@/components/alert/Message'
|
||||
|
||||
import { useKUNGalgameMessageStore } from '@/store/modules/message'
|
||||
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const { showKUNGalgameLanguage } = storeToRefs(useKUNGalgameSettingsStore())
|
||||
const { isShowCapture, isCaptureSuccessful } = storeToRefs(
|
||||
useKUNGalgameMessageStore()
|
||||
)
|
||||
// Current language
|
||||
const questions = ref<Question[]>([])
|
||||
|
||||
// Initialize
|
||||
questions.value =
|
||||
showKUNGalgameLanguage.value === 'en' ? questionsEN : questionsCN
|
||||
|
||||
// Watch for changes in the language setting
|
||||
watch(showKUNGalgameLanguage, () => {
|
||||
questions.value =
|
||||
showKUNGalgameLanguage.value === 'en' ? questionsEN : questionsCN
|
||||
})
|
||||
|
||||
// Function to randomly select a question
|
||||
const randomizeQuestion = () => {
|
||||
// Generate a random integer between 0 and the number of questions minus 1
|
||||
return Math.floor(Math.random() * questions.value.length)
|
||||
}
|
||||
|
||||
// User's input answer
|
||||
const userAnswers = ref('')
|
||||
// Current question index
|
||||
const currentQuestionIndex = ref(randomizeQuestion())
|
||||
// Current question
|
||||
const currentQuestion = ref(questions.value[currentQuestionIndex.value])
|
||||
// Error count
|
||||
const errorCounter = ref(0)
|
||||
const expectedKeys = ref(['k', 'u', 'n'])
|
||||
const currentIndex = ref(0)
|
||||
// Whether to show hints
|
||||
const isShowHint = ref(false)
|
||||
// Whether to show the answer
|
||||
const isShowAnswer = ref(false)
|
||||
|
||||
const resetStatus = () => {
|
||||
userAnswers.value = ''
|
||||
currentQuestionIndex.value = randomizeQuestion()
|
||||
currentQuestion.value = questions.value[currentQuestionIndex.value]
|
||||
errorCounter.value = 0
|
||||
currentIndex.value = 0
|
||||
isShowHint.value = false
|
||||
isShowAnswer.value = false
|
||||
}
|
||||
|
||||
// Listen to keyboard events
|
||||
const checkKeyPress = (event: KeyboardEvent) => {
|
||||
const pressedKey = event.key
|
||||
|
||||
if (pressedKey === expectedKeys.value[currentIndex.value]) {
|
||||
// When the user presses the expected key
|
||||
if (currentIndex.value === expectedKeys.value.length - 1) {
|
||||
// If the last key "n" has been pressed, trigger the corresponding logic
|
||||
isShowAnswer.value = true
|
||||
} else {
|
||||
// Otherwise, continue to the next expected key
|
||||
currentIndex.value++
|
||||
}
|
||||
} else {
|
||||
// If the wrong key is pressed, start checking again
|
||||
currentIndex.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Submit the answer
|
||||
const submitAnswer = () => {
|
||||
const correctOption = currentQuestion.value.correctOption
|
||||
|
||||
if (userAnswers.value === correctOption) {
|
||||
// Correct answer
|
||||
// Set the validation as successful
|
||||
isCaptureSuccessful.value = true
|
||||
// Close the panel
|
||||
isShowCapture.value = false
|
||||
Message(
|
||||
'Human-machine identity verification successful ~',
|
||||
'人机身份验证通过 ~',
|
||||
'success'
|
||||
)
|
||||
resetStatus()
|
||||
} else {
|
||||
// Wrong answer
|
||||
errorCounter.value++
|
||||
|
||||
Message('Wrong answer!', '回答错误!', 'warn')
|
||||
|
||||
// Randomly select a new question
|
||||
const randomIndex = randomizeQuestion()
|
||||
currentQuestionIndex.value = randomIndex
|
||||
userAnswers.value = ''
|
||||
|
||||
// Show hints if the error count is greater than or equal to 3
|
||||
if (errorCounter.value >= 3) {
|
||||
isShowHint.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close panel
|
||||
const handleCloseCapture = () => {
|
||||
isShowCapture.value = false
|
||||
resetStatus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="#teleported" :disabled="isShowCapture">
|
||||
<Transition name="capture">
|
||||
<div>
|
||||
<!-- Mask -->
|
||||
<div
|
||||
class="mask"
|
||||
@keydown="checkKeyPress($event)"
|
||||
tabindex="0"
|
||||
v-if="isShowCapture"
|
||||
>
|
||||
<div class="validate">
|
||||
<!-- Title -->
|
||||
<div class="title">
|
||||
<!-- <span>{{ `❮` }}</span> -->
|
||||
<h2>{{ $tm('AlertInfo.capture.title') }}</h2>
|
||||
<!-- <span>{{ `❯` }}</span> -->
|
||||
</div>
|
||||
<p class="question">{{ currentQuestion.text }}</p>
|
||||
|
||||
<!-- Options -->
|
||||
<div class="select">
|
||||
<label
|
||||
v-for="(option, index) in currentQuestion.options"
|
||||
:key="index"
|
||||
>
|
||||
<input type="radio" v-model="userAnswers" :value="option" />
|
||||
{{ option }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Submit buttons -->
|
||||
<div class="btn">
|
||||
<button @click="submitAnswer">
|
||||
{{ $tm('AlertInfo.capture.submit') }}
|
||||
</button>
|
||||
<button @click="handleCloseCapture">
|
||||
{{ $tm('AlertInfo.capture.close') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Hints -->
|
||||
<!-- tabindex allows this element to be focused on the page -->
|
||||
<div class="hint-container">
|
||||
<div v-if="isShowHint" class="hint">
|
||||
<div>{{ $tm('AlertInfo.capture.hint1') }}</div>
|
||||
<div>
|
||||
{{ $tm('AlertInfo.capture.hint2') }}
|
||||
<span>kun</span>
|
||||
{{ $tm('AlertInfo.capture.hint3') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isShowAnswer" class="answer">
|
||||
<div>{{ $tm('AlertInfo.capture.hint4') }}</div>
|
||||
<a
|
||||
href="https://github.com/KUN1007/kun-galgame-vue/tree/remove-server/src/components/capture"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ $tm('AlertInfo.capture.answer') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mask {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--kungalgame-mask-color-0);
|
||||
display: flex;
|
||||
transition: opacity 0.3s ease;
|
||||
color: var(--kungalgame-font-color-3);
|
||||
}
|
||||
|
||||
.validate {
|
||||
width: 300px;
|
||||
min-height: 300px;
|
||||
margin: auto;
|
||||
padding: 17px;
|
||||
background-color: var(--kungalgame-trans-white-2);
|
||||
border: 1px solid var(--kungalgame-blue-1);
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 17px;
|
||||
color: var(--kungalgame-blue-4);
|
||||
}
|
||||
|
||||
.question {
|
||||
font-size: 17px;
|
||||
margin-bottom: 20px;
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
.select {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
button {
|
||||
width: 77px;
|
||||
padding: 5px;
|
||||
color: var(--kungalgame-blue-4);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
border-radius: 5px;
|
||||
background-color: var(--kungalgame-trans-white-9);
|
||||
transition: all 0.2s;
|
||||
&:hover {
|
||||
color: var(--kungalgame-white);
|
||||
background-color: var(--kungalgame-blue-4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hint-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: end;
|
||||
justify-content: end;
|
||||
font-style: oblique;
|
||||
.hint {
|
||||
width: 100%;
|
||||
font-size: 10px;
|
||||
span {
|
||||
color: var(--kungalgame-pink-4);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.answer {
|
||||
width: 100%;
|
||||
div {
|
||||
font-size: 10px;
|
||||
}
|
||||
a {
|
||||
color: var(--kungalgame-blue-5);
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active {
|
||||
transition: all 0.2s;
|
||||
border: 2px solid var(--kungalgame-pink-3);
|
||||
}
|
||||
|
||||
.capture-enter-from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.capture-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.capture-enter-from .validate,
|
||||
.capture-leave-to .validate {
|
||||
-webkit-transform: scale(1.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
</style>
|
|
@ -1,7 +1,7 @@
|
|||
import { createApp } from './main'
|
||||
import { createKUNGalgameRouter } from './router'
|
||||
import { setupPinia } from './store'
|
||||
import i18n from '@/language/i18n'
|
||||
import createI18n from '@/language/i18n'
|
||||
import '@/styles/index.scss'
|
||||
|
||||
const router = createKUNGalgameRouter()
|
||||
|
@ -9,6 +9,8 @@ const pinia = setupPinia()
|
|||
|
||||
const { app } = createApp()
|
||||
|
||||
export const i18n = createI18n()
|
||||
|
||||
app.use(router).use(pinia).use(i18n)
|
||||
|
||||
if (window.__pinia) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createApp } from './main'
|
|||
|
||||
import { createKUNGalgameRouter } from './router'
|
||||
import { setupPinia } from './store'
|
||||
import i18n from '@/language/i18n'
|
||||
import createI18n from '@/language/i18n'
|
||||
|
||||
import { renderToString } from '@vue/server-renderer'
|
||||
|
||||
|
@ -46,9 +46,11 @@ const renderPreloadLinks = (
|
|||
|
||||
export const render = async (
|
||||
ctx: ParameterizedContext,
|
||||
manifest: Record<string, string[]>
|
||||
): Promise<[string, string, string]> => {
|
||||
manifest: Record<string, string[]>,
|
||||
options: { language: string; country: string }
|
||||
) => {
|
||||
const { app } = createApp()
|
||||
const { language, country } = options
|
||||
|
||||
// router
|
||||
const router = createKUNGalgameRouter()
|
||||
|
@ -63,7 +65,9 @@ export const render = async (
|
|||
const renderedPinia = JSON.stringify(pinia.state.value)
|
||||
|
||||
// i18n
|
||||
app.use(i18n)
|
||||
app.use(createI18n(
|
||||
language.includes('zh') ? 'zh' : 'en',
|
||||
))
|
||||
|
||||
const renderCtx: { modules?: string[] } = {}
|
||||
|
||||
|
@ -71,5 +75,9 @@ export const render = async (
|
|||
|
||||
const renderedLinks = renderPreloadLinks(renderCtx.modules, manifest)
|
||||
|
||||
return [renderedHtml, renderedPinia, renderedLinks]
|
||||
const renderedTeleports = renderCtx.teleports as {
|
||||
'#teleported': string
|
||||
}
|
||||
|
||||
return [renderedHtml, renderedPinia, renderedLinks, renderedTeleports]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createI18n } from 'vue-i18n'
|
||||
import { createI18n as _createI18n } from 'vue-i18n'
|
||||
// 读取本地存储中的语言配置
|
||||
import { KUNGalgameLanguage } from '@/utils/getDefaultEnv'
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { KUNGalgameLanguage } from '@/utils/getDefaultEnv'
|
|||
import zh from './zh'
|
||||
import en from './en'
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: KUNGalgameLanguage,
|
||||
const createI18n = (language?: string) => _createI18n({
|
||||
locale: language || KUNGalgameLanguage,
|
||||
legacy: false,
|
||||
messages: {
|
||||
zh,
|
||||
|
@ -15,4 +15,4 @@ const i18n = createI18n({
|
|||
},
|
||||
})
|
||||
|
||||
export default i18n
|
||||
export default createI18n
|
||||
|
|
16
src/router/guard/index.ts
Normal file
16
src/router/guard/index.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Router } from 'vue-router'
|
||||
import { createPermission } from './permission'
|
||||
import { i18n } from '@/entry-client'
|
||||
|
||||
const createPageTitle = (router: Router) => {
|
||||
router.beforeEach((to) => {
|
||||
const title = to.meta.title as string
|
||||
document.title = i18n.global.tm(`router.${title}`)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
export function setupRouterGuard(router: Router) {
|
||||
createPermission(router)
|
||||
createPageTitle(router)
|
||||
}
|
|
@ -5,25 +5,31 @@ import vue from '@vitejs/plugin-vue'
|
|||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue(), visualizer() as PluginOption],
|
||||
/* Set the 'src' alias to '@' */
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
export default defineConfig(({ mode, ssrBuild, command }) => {
|
||||
return {
|
||||
plugins: [vue(), visualizer() as PluginOption],
|
||||
/* Set the 'src' alias to '@' */
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
drop: ['console', 'debugger'],
|
||||
},
|
||||
build: {
|
||||
// Dist dir name
|
||||
assetsDir: 'kun',
|
||||
},
|
||||
// Suppress i18n warnings
|
||||
define: {
|
||||
__VUE_I18N_FULL_INSTALL__: true,
|
||||
__VUE_I18N_LEGACY_API__: false,
|
||||
__INTLIFY_PROD_DEVTOOLS__: false,
|
||||
},
|
||||
esbuild:
|
||||
command === 'serve'
|
||||
? {}
|
||||
: {
|
||||
drop: ['console', 'debugger'],
|
||||
},
|
||||
build: {
|
||||
// Dist dir name
|
||||
assetsDir: 'kun',
|
||||
},
|
||||
server: { host: '127.0.0.1', port: 1007 },
|
||||
// Suppress i18n warnings
|
||||
define: {
|
||||
__VUE_I18N_FULL_INSTALL__: true,
|
||||
__VUE_I18N_LEGACY_API__: false,
|
||||
__INTLIFY_PROD_DEVTOOLS__: false,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue