language.vue 3.8 KB
<template>
  <view class="page">
    <view class="header-hero" :style="{ paddingTop: statusBarHeight + 'px' }">
      <view class="top-bar">
        <view class="top-left" @click="goBack">
          <AppIcon name="chevronLeft" size="sm" color="white" />
        </view>
        <view class="top-center">
          <text class="page-title">{{ t('language.title') }}</text>
          <LocationPicker />
        </view>
        <view class="top-right" @click="isMenuOpen = true">
          <AppIcon name="menu" size="sm" color="white" />
        </view>
      </view>
    </view>

    <view class="content">
      <view class="intro">
        <text class="intro-title">{{ t('language.selectLanguage') }}</text>
        <text class="intro-desc">Choose your preferred language for the app</text>
      </view>
      <view class="lang-list">
        <view
          v-for="lang in languages"
          :key="lang.code"
          class="lang-card"
          :class="{ active: locale === lang.code }"
          @click="handleChange(lang.code)"
        >
          <text class="lang-flag">{{ lang.flag }}</text>
          <text class="lang-name">{{ t(lang.nameKey) }}</text>
          <view v-if="locale === lang.code" class="lang-check"><AppIcon name="check" size="sm" color="white" /></view>
        </view>
      </view>
    </view>

    <SideMenu v-model="isMenuOpen" />
  </view>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { setLocale } from '../../utils/i18n'
import AppIcon from '../../components/AppIcon.vue'
import SideMenu from '../../components/SideMenu.vue'
import LocationPicker from '../../components/LocationPicker.vue'
import { getStatusBarHeight } from '../../utils/statusBar'

const { t, locale } = useI18n()
const statusBarHeight = getStatusBarHeight()
const isMenuOpen = ref(false)
const languages = [
  { code: 'en' as const, nameKey: 'language.english', flag: '🇺🇸' },
  { code: 'zh' as const, nameKey: 'language.chinese', flag: '🇨🇳' },
]

const goBack = () => {
  const pages = getCurrentPages()
  if (pages.length > 1) {
    uni.navigateBack()
  } else {
    uni.redirectTo({ url: '/pages/index/index' })
  }
}

const handleChange = (code: 'en' | 'zh') => {
  setLocale(code)
  uni.showToast({ title: t('language.changed'), icon: 'success' })
}
</script>

<style scoped>
.page {
  min-height: 100vh;
  background: #f9fafb;
}

.header-hero {
  background: linear-gradient(135deg, var(--theme-primary), var(--theme-primary-dark));
  padding: 16rpx 32rpx 24rpx;
}

.top-bar {
  height: 96rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.top-left,
.top-right {
  width: 64rpx;
  height: 64rpx;
  border-radius: 999rpx;
  background: rgba(255, 255, 255, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
}

.top-center {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.page-title {
  font-size: 34rpx;
  font-weight: 600;
  color: #fff;
}

.content {
  padding: 48rpx;
}

.intro {
  margin-bottom: 32rpx;
}

.intro-title {
  font-size: 32rpx;
  font-weight: 600;
  color: #111827;
  display: block;
  margin-bottom: 8rpx;
}

.intro-desc {
  font-size: 28rpx;
  color: #6b7280;
}

.lang-card {
  background: #fff;
  padding: 32rpx;
  border-radius: 20rpx;
  margin-bottom: 24rpx;
  display: flex;
  align-items: center;
  gap: 32rpx;
  border: 3rpx solid #e5e7eb;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}

.lang-card.active {
  border-color: var(--theme-primary);
  background: var(--theme-primary-light);
}

.lang-flag {
  font-size: 60rpx;
}

.lang-name {
  font-size: 34rpx;
  font-weight: 600;
  color: #111827;
  flex: 1;
}

.lang-check {
  width: 48rpx;
  height: 48rpx;
  background: var(--theme-primary);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>