mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
A pass over every file the branch touched, after the iOS animation hunt left tries and reverts behind it. Removed what nothing reaches: the view-transition rule for a transition no code starts, an unreachable guard in the transition hook, a no-op KeepAlive key branch, a sign-in guard the menu already enforces, usage-dialog wrappers that only forwarded to the store, a duplicated modifier-click check and card filter (isPlainClick / listedTools), a test that hand-rolled listedTools, a drawer-era fixture parameter. auth-flow.js folded into auth-redirect.js. Comments cut to what the code cannot say itself — file headers of a few lines, the measured iOS reasons, non-obvious orderings — and stale ones fixed (Nav under KeepAlive, Home.vue reusing DEFAULT_META, "from Nav", enabledCards). AGENTS.md sections tightened to the code as it is now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013GbLTGMZ45MV78qd2tHoco
121 lines
4.2 KiB
Vue
121 lines
4.2 KiB
Vue
<template>
|
|
<Achievements ref="achievementsRef" />
|
|
<main id="mainpart" class="mx-auto w-full px-4 jn-container">
|
|
<div class="rounded-md">
|
|
<IPCheck />
|
|
<Connectivity />
|
|
<WebRTC />
|
|
<DNSLeaks />
|
|
<SpeedTest />
|
|
<AdvancedTools ref="advancedToolsRef" />
|
|
</div>
|
|
</main>
|
|
<FloatingDock :ready="showMaskButton" :mask-active="infoMaskLevel > 0">
|
|
<InfoMask :showMaskButton.value="showMaskButton" :infoMaskLevel.value="infoMaskLevel"
|
|
:toggleInfoMask="toggleInfoMask" />
|
|
<ShareReport ref="shareReportRef" />
|
|
<IPHistory />
|
|
<QueryIP ref="queryIPRef" />
|
|
</FloatingDock>
|
|
<HelpModal ref="helpModalRef" />
|
|
<Additional />
|
|
<Footer />
|
|
</template>
|
|
|
|
<script setup>
|
|
// The homepage (`/`): every top-level section plus the Advanced Tools cards;
|
|
// what every route shares lives in App.vue.
|
|
//
|
|
// Components — the test sections and the always-visible chrome load
|
|
// synchronously; everything the first paint can't show (dialogs, the
|
|
// below-fold Additional/Footer) is an async component so its code stays
|
|
// out of the route chunk and out of the mount's critical path. Their
|
|
// template refs are null until the chunk lands — consumers (use-shortcuts)
|
|
// must optional-chain.
|
|
import IPCheck from './IpInfos.vue';
|
|
import Connectivity from './ConnectivityTest.vue';
|
|
import WebRTC from './WebRtcTest.vue';
|
|
import DNSLeaks from './DnsLeaksTest.vue';
|
|
import SpeedTest from './SpeedTest.vue';
|
|
import AdvancedTools from './Advanced.vue';
|
|
import InfoMask from './widgets/InfoMask.vue';
|
|
import FloatingDock from './widgets/FloatingDock.vue';
|
|
|
|
// Vue + Store
|
|
import { ref, computed, onMounted, defineAsyncComponent } from 'vue';
|
|
|
|
// Async (off-critical-path) components
|
|
const Additional = defineAsyncComponent(() => import('./Additional.vue'));
|
|
const Footer = defineAsyncComponent(() => import('./Footer.vue'));
|
|
const Achievements = defineAsyncComponent(() => import('./Achievements.vue'));
|
|
const QueryIP = defineAsyncComponent(() => import('./widgets/QueryIP.vue'));
|
|
const HelpModal = defineAsyncComponent(() => import('./widgets/Help.vue'));
|
|
const IPHistory = defineAsyncComponent(() => import('./widgets/IPHistory.vue'));
|
|
const ShareReport = defineAsyncComponent(() => import('./report/ShareReportDialog.vue'));
|
|
import { useMainStore } from '@/store';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
// Composables
|
|
import { useInfoMask } from '@/composables/use-info-mask.js';
|
|
import { useRefreshOrchestrator } from '@/composables/use-refresh-orchestrator.js';
|
|
import { useShortcuts } from '@/composables/use-shortcuts.js';
|
|
import { useSectionTracking } from '@/composables/use-section-tracking.js';
|
|
import { useDocumentMeta } from '@/composables/use-document-meta.js';
|
|
|
|
defineOptions({ name: 'Home' });
|
|
|
|
const { t } = useI18n();
|
|
const store = useMainStore();
|
|
const configs = computed(() => store.configs);
|
|
const userPreferences = computed(() => store.userPreferences);
|
|
|
|
// Template refs — UI chrome only; the test sections are reached through the
|
|
// command bus (utils/app-commands.js), not refs.
|
|
const achievementsRef = ref(null);
|
|
const queryIPRef = ref(null);
|
|
const helpModalRef = ref(null);
|
|
const shareReportRef = ref(null);
|
|
const advancedToolsRef = ref(null);
|
|
|
|
// Info mask
|
|
const { infoMaskLevel, isInfosLoaded, showMaskButton, toggleInfoMask } = useInfoMask({
|
|
store,
|
|
t,
|
|
});
|
|
|
|
// Refresh / initial load sequence
|
|
const { loadingControl } = useRefreshOrchestrator({
|
|
store,
|
|
t,
|
|
userPreferences,
|
|
infoMaskLevel,
|
|
});
|
|
|
|
// Shortcuts
|
|
const { loadShortcuts } = useShortcuts({
|
|
refs: {
|
|
queryIPRef, helpModalRef, shareReportRef, advancedToolsRef,
|
|
isInfosLoaded, toggleInfoMask,
|
|
},
|
|
store, t, configs, userPreferences,
|
|
});
|
|
|
|
// Scroll monitoring + section tracking (logic from widgets/Patch.vue)
|
|
useSectionTracking();
|
|
|
|
// Localized homepage head. Provide title/description explicitly via t() rather
|
|
// than leaning on use-document-meta's DEFAULT_META snapshot: that snapshot is
|
|
// taken at module load, before the (now async) locale messages land, so it would
|
|
// pin the head to index.html's English title.
|
|
useDocumentMeta(() => ({
|
|
title: t('page.title'),
|
|
description: t('page.description'),
|
|
canonical: `${window.location.origin}/`,
|
|
}));
|
|
|
|
onMounted(() => {
|
|
loadingControl();
|
|
loadShortcuts();
|
|
});
|
|
</script>
|