feat: init
This commit is contained in:
10
src/App.vue
Normal file
10
src/App.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IonApp>
|
||||
<Suspense>
|
||||
<IonRouterOutlet />
|
||||
</Suspense>
|
||||
</IonApp>
|
||||
</template>
|
||||
47
src/components/layout/default.vue
Normal file
47
src/components/layout/default.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { cellular, chatboxEllipses, compass, personCircle, swapHorizontal } from "ionicons/icons";
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-tabs>
|
||||
<ion-router-outlet />
|
||||
<ion-tab-bar slot="bottom">
|
||||
<ion-tab-button tab="home" href="/layout/home">
|
||||
<div class="flex-col-center gap-1">
|
||||
<ion-icon aria-hidden="true" :icon="compass" class="icon" />
|
||||
<ion-label>{{ t('tabs.home') }}</ion-label>
|
||||
</div>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="notify" href="/layout/notify">
|
||||
<div class="flex-col-center gap-1">
|
||||
<ion-icon aria-hidden="true" :icon="chatboxEllipses" class="icon" />
|
||||
<ion-label>{{ t('tabs.notify') }}</ion-label>
|
||||
</div>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="user" href="/layout/user">
|
||||
<div class="flex-col-center gap-1">
|
||||
<ion-icon aria-hidden="true" :icon="personCircle" class="icon" />
|
||||
<ion-label>{{ t('tabs.user') }}</ion-label>
|
||||
</div>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
ion-tab-bar {
|
||||
height: 60px;
|
||||
--background: var(--ion-background-color);
|
||||
box-shadow: 0px 0px 12px rgba(45, 213, 90, 0.21);
|
||||
padding-bottom: var(--ion-safe-area-bottom);
|
||||
}
|
||||
.icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
15
src/locales/index.ts
Normal file
15
src/locales/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createI18n } from "vue-i18n";
|
||||
import zhCN from "./zh-CN.json";
|
||||
|
||||
export type MessageSchema = typeof zhCN;
|
||||
|
||||
const i18n = createI18n<MessageSchema, "zh-CN">({
|
||||
legacy: false,
|
||||
locale: "zh-CN",
|
||||
fallbackLocale: "zh-CN",
|
||||
messages: {
|
||||
"zh-CN": zhCN,
|
||||
},
|
||||
});
|
||||
|
||||
export { i18n };
|
||||
10
src/locales/zh-CN.json
Normal file
10
src/locales/zh-CN.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"tabs": {
|
||||
"home": "首页",
|
||||
"notify": "通知",
|
||||
"user": "我的"
|
||||
},
|
||||
"home": {
|
||||
"title": "首页"
|
||||
}
|
||||
}
|
||||
84
src/main.ts
Normal file
84
src/main.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { IonicVue } from "@ionic/vue";
|
||||
import { createPinia } from "pinia";
|
||||
import VConsole from "vconsole";
|
||||
import { useRegisterSW } from "virtual:pwa-register/vue";
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import { i18n } from "./locales";
|
||||
import { router } from "./router";
|
||||
|
||||
/* Core CSS required for Ionic components to work properly */
|
||||
import "@ionic/vue/css/core.css";
|
||||
/* Basic CSS for apps built with Ionic */
|
||||
import "@ionic/vue/css/normalize.css";
|
||||
import "@ionic/vue/css/structure.css";
|
||||
|
||||
import "@ionic/vue/css/typography.css";
|
||||
/* Optional CSS utils that can be commented out */
|
||||
import "@ionic/vue/css/padding.css";
|
||||
import "@ionic/vue/css/float-elements.css";
|
||||
import "@ionic/vue/css/text-alignment.css";
|
||||
import "@ionic/vue/css/text-transformation.css";
|
||||
import "@ionic/vue/css/flex-utils.css";
|
||||
|
||||
/**
|
||||
* Ionic Dark Mode
|
||||
* -----------------------------------------------------
|
||||
* For more info, please see:
|
||||
* https://ionicframework.com/docs/theming/dark-mode
|
||||
*/
|
||||
|
||||
import "@ionic/vue/css/display.css";
|
||||
// import "@ionic/vue/css/palettes/dark.system.css";
|
||||
// import "@ionic/vue/css/palettes/dark.always.css";
|
||||
// import "@ionic/vue/css/palettes/dark.class.css";
|
||||
import "@/theme/index.css";
|
||||
|
||||
// 注册 PWA Service Worker(使用 Vue 3 Composition API)
|
||||
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
|
||||
onRegistered(registration) {
|
||||
console.log("[PWA] Service Worker registered:", registration);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.error("[PWA] Service Worker registration failed:", error);
|
||||
},
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
// 监听 PWA 状态
|
||||
watch(offlineReady, (ready) => {
|
||||
if (ready) {
|
||||
console.log("[PWA] App ready to work offline.");
|
||||
}
|
||||
});
|
||||
|
||||
watch(needRefresh, (refresh) => {
|
||||
if (refresh) {
|
||||
console.log("[PWA] New content available, please refresh.");
|
||||
}
|
||||
});
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
const vConsole = new VConsole();
|
||||
globalThis.vConsole = vConsole;
|
||||
console.log("VConsole is enabled in development mode.");
|
||||
}
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
const app = createApp(App)
|
||||
.use(IonicVue, {
|
||||
backButtonText: "返回",
|
||||
mode: "ios",
|
||||
statusTap: true,
|
||||
swipeBackEnabled: true,
|
||||
// rippleEffect: true,
|
||||
// animated: false,
|
||||
})
|
||||
.use(pinia)
|
||||
.use(router)
|
||||
.use(i18n);
|
||||
|
||||
router.isReady().then(() => {
|
||||
app.mount("#app");
|
||||
});
|
||||
18
src/router/auth.ts
Normal file
18
src/router/auth.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { RouteRecordRaw } from "vue-router";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/auth/login",
|
||||
component: () => import("@/views/auth/login/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/auth/signup",
|
||||
component: () => import("@/views/auth/signup/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "/auth/term",
|
||||
component: () => import("@/views/auth/term.vue"),
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
7
src/router/guard.ts
Normal file
7
src/router/guard.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Router } from "vue-router";
|
||||
|
||||
export function createRouterGuard(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
next();
|
||||
});
|
||||
}
|
||||
35
src/router/index.ts
Normal file
35
src/router/index.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import type { RouteRecordRaw } from "vue-router";
|
||||
import { createRouter, createWebHistory } from "@ionic/vue-router";
|
||||
import authRoutes from "./auth";
|
||||
import { createRouterGuard } from "./guard";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
redirect: "/layout/home",
|
||||
},
|
||||
{
|
||||
path: "/:pathMatch(.*)*",
|
||||
redirect: "/layout/home",
|
||||
},
|
||||
// ...authRoutes,
|
||||
{
|
||||
path: "/layout",
|
||||
component: () => import("@/components/layout/default.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "home",
|
||||
component: () => import("@/views/home/index.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
});
|
||||
|
||||
createRouterGuard(router);
|
||||
|
||||
export { router };
|
||||
3
src/theme/index.css
Normal file
3
src/theme/index.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@import "tailwindcss";
|
||||
@config "../../tailwind.config.ts";
|
||||
@import "./ionic.css"
|
||||
4
src/theme/ionic.css
Normal file
4
src/theme/ionic.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.ion-toolbar {
|
||||
--background: var(--ion-color-primary-contrast);
|
||||
--min-height: 50px;
|
||||
}
|
||||
19
src/views/home/index.vue
Normal file
19
src/views/home/index.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script lang='ts' setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header class="ion-no-border">
|
||||
<ion-toolbar class="ion-toolbar">
|
||||
<ion-button slot="start" fill="clear" class="z-1" @click="$router.push('/global-menu')">
|
||||
<IconParkOutlineApplicationMenu slot="icon-only" />
|
||||
</ion-button>
|
||||
<ion-title>{{ $t('home.title') }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content :fullscreen="true" class="ion-padding" />
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped></style>
|
||||
34
src/vite-env.d.ts
vendored
Normal file
34
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-plugin-pwa/client" />
|
||||
/// <reference types="unplugin-icons/types/vue" />
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import type { MessageSchema } from "@/locales";
|
||||
import {
|
||||
DefineDateTimeFormat,
|
||||
DefineLocaleMessage,
|
||||
DefineNumberFormat,
|
||||
} from "vue-i18n";
|
||||
import "vue-router";
|
||||
|
||||
export {};
|
||||
|
||||
declare module "vue-i18n" {
|
||||
// define the locale messages schema
|
||||
export interface DefineLocaleMessage extends MessageSchema {
|
||||
}
|
||||
|
||||
// define the datetime format schema
|
||||
export interface DefineDateTimeFormat {
|
||||
}
|
||||
|
||||
// define the number format schema
|
||||
export interface DefineNumberFormat {
|
||||
}
|
||||
}
|
||||
|
||||
declare module "vue-router" {
|
||||
interface RouteMeta {
|
||||
requiresAuth: ? boolean;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user