Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vitepress/data/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export const en: LocaleMessages = {
alsoDownload: 'Or download directly from:',
},

region: {
blocked: 'Downloads are not available in your country or region',
hint: 'Sorry, this content is currently unavailable in your region.',
},

history: {
title: 'Historical Releases',
subtitle: 'Select a release, choose source, then download the installer.',
Expand Down
4 changes: 4 additions & 0 deletions .vitepress/data/locales/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export interface LocaleMessages {
historicalBtn: string;
alsoDownload: string;
};
region: {
blocked: string;
hint: string;
};
history: {
title: string;
subtitle: string;
Expand Down
5 changes: 5 additions & 0 deletions .vitepress/data/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export const zh: LocaleMessages = {
alsoDownload: '你也可以直接在下方的链接中下载',
},

region: {
blocked: '您所在的国家或地区暂不支持下载',
hint: '很抱歉,该内容目前无法在您的所在地区提供。',
},

history: {
title: '历史版本下载',
subtitle: '选择版本并切换下载源后下载对应安装包。',
Expand Down
30 changes: 29 additions & 1 deletion .vitepress/theme/components/HistoryReleases.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { useData } from 'vitepress';
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
import { getMessages, type Lang } from '../../data/i18n';
import { useRegionGuard } from '../composables/useRegionGuard';

interface ReleaseAsset {
name: string;
Expand Down Expand Up @@ -54,6 +55,13 @@ const messages = computed(() => {
return getMessages(currentLang).history;
});

// biome-ignore lint/correctness/noUnusedVariables: used in Vue template
const {
blocked,
message: blockedMessage,
hint: blockedHint,
} = useRegionGuard();

function formatDate(value: string) {
if (!value) return '';
const date = new Date(value);
Expand Down Expand Up @@ -282,7 +290,11 @@ function handleOutsideClick(event: MouseEvent) {
</div>
</div>

<div v-if="selectedAssets.length > 0" class="history-assets">
<div v-if="blocked" class="history-assets-blocked">
<div>{{ blockedMessage }}</div>
<div class="history-assets-blocked-hint">{{ blockedHint }}</div>
</div>
<div v-else-if="selectedAssets.length > 0" class="history-assets">
<a
v-for="asset in selectedAssets"
:key="asset.href"
Expand Down Expand Up @@ -618,6 +630,22 @@ function handleOutsideClick(event: MouseEvent) {
font-size: 0.9rem;
}

.history-assets-blocked {
margin-top: 0.6rem;
padding: 0.75rem 1rem;
border: 1px dashed var(--vp-c-divider);
border-radius: 12px;
background: var(--vp-c-bg-soft);
text-align: center;
color: var(--vp-c-text-2);
}

.history-assets-blocked-hint {
margin-top: 0.35rem;
font-size: 0.9rem;
color: var(--vp-c-text-3);
}

.history-release-link {
color: var(--vp-c-text-2);
font-size: 0.9rem;
Expand Down
43 changes: 35 additions & 8 deletions .vitepress/theme/components/MirrorGrid.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { useRegionGuard } from '../composables/useRegionGuard';

interface MirrorItem {
href: string;
label: string;
Expand All @@ -7,18 +9,27 @@ interface MirrorItem {
defineProps<{
items: MirrorItem[];
}>();

// biome-ignore lint/correctness/noUnusedVariables: used in Vue template
const { blocked, message, hint } = useRegionGuard();
</script>

<template>
<div class="mirror-grid">
<a
v-for="item in items"
:key="item.href"
:href="item.href"
class="mirror-btn"
>
{{ item.label }}
</a>
<div v-if="blocked" class="mirror-blocked">
<div>{{ message }}</div>
<div class="mirror-blocked-hint">{{ hint }}</div>
</div>
<template v-else>
<a
v-for="item in items"
:key="item.href"
:href="item.href"
class="mirror-btn"
>
{{ item.label }}
</a>
</template>
</div>
</template>

Expand Down Expand Up @@ -48,6 +59,22 @@ defineProps<{
color: var(--vp-c-brand-1);
}

.mirror-blocked {
grid-column: 1 / -1;
padding: 0.75rem 1rem;
background: var(--vp-c-bg-soft);
border: 1px dashed var(--vp-c-divider);
border-radius: 8px;
text-align: center;
color: var(--vp-c-text-2);
}

.mirror-blocked-hint {
margin-top: 0.35rem;
font-size: 0.875rem;
color: var(--vp-c-text-3);
}

@media (max-width: 768px) {
.mirror-grid {
grid-template-columns: 1fr;
Expand Down
32 changes: 32 additions & 0 deletions .vitepress/theme/components/RegionGate.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
import { useRegionGuard } from '../composables/useRegionGuard';

// biome-ignore lint/correctness/noUnusedVariables: used in Vue template
const { blocked, message, hint } = useRegionGuard();
</script>

<template>
<div v-if="blocked" class="region-blocked">
<div>{{ message }}</div>
<div class="region-blocked-hint">{{ hint }}</div>
</div>
<slot v-else />
</template>

<style scoped>
.region-blocked {
display: inline-block;
padding: 0.75rem 1rem;
background: var(--vp-c-bg-soft);
border: 1px dashed var(--vp-c-divider);
border-radius: 8px;
text-align: center;
color: var(--vp-c-text-2);
}

.region-blocked-hint {
margin-top: 0.35rem;
font-size: 0.875rem;
color: var(--vp-c-text-3);
}
</style>
66 changes: 66 additions & 0 deletions .vitepress/theme/composables/useRegionGuard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useData } from 'vitepress';
import { computed, onMounted, ref } from 'vue';
import { getMessages, type Lang } from '../../data/i18n';

const TRACE_URL = 'https://www.cloudflare.com/cdn-cgi/trace';
const TRACE_TIMEOUT = 5000;

const CHINA_TIME_ZONES = new Set([
'Asia/Shanghai',
'Asia/Chongqing',
'Asia/Harbin',
'Asia/Urumqi',
'Asia/Kashgar',
'PRC',
]);

const blocked = ref(false);
let checkStarted = false;

function isChinaTimeZone(): boolean {
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? '';
return CHINA_TIME_ZONES.has(timeZone);
}

async function requestTraceLocation(): Promise<string> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), TRACE_TIMEOUT);
try {
const response = await fetch(TRACE_URL, {
cache: 'no-store',
signal: controller.signal,
});
if (!response.ok) return '';
const text = await response.text();
return (/(?:^|\n)loc=([^\s\r]+)/.exec(text)?.[1] ?? '').toUpperCase();
} catch {
return '';
} finally {
clearTimeout(timer);
}
}

function startRegionCheck() {
if (checkStarted) return;
checkStarted = true;
if (isChinaTimeZone()) {
blocked.value = true;
return;
}
void requestTraceLocation().then((loc) => {
if (loc === 'CN') blocked.value = true;
});
}

export function useRegionGuard() {
const { lang } = useData();
onMounted(startRegionCheck);
const region = computed(
() => getMessages((lang.value || 'zh-CN') as Lang).region,
);
return {
blocked,
message: computed(() => region.value.blocked),
hint: computed(() => region.value.hint),
};
}
2 changes: 2 additions & 0 deletions .vitepress/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import HistoryReleases from './components/HistoryReleases.vue';
import HomeUnderline from './components/HomeUnderline.vue';
import ImageGallery from './components/ImageGallery.vue';
import MirrorGrid from './components/MirrorGrid.vue';
import RegionGate from './components/RegionGate.vue';
import SiteFooter from './components/SiteFooter.vue';
import VideoSection from './components/VideoSection.vue';

Expand All @@ -36,6 +37,7 @@ export default {
app.component('Copy', CopyText);
// 注册自定义组件
app.component('MirrorGrid', MirrorGrid);
app.component('RegionGate', RegionGate);
app.component('AboutPage', AboutPage);
app.component('HistoryReleases', HistoryReleases);
app.component('VideoSection', VideoSection);
Expand Down
4 changes: 4 additions & 0 deletions src/download.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ keywords: PCL下载,Minecraft启动器下载,PCL社区版下载,启动器下载

如果你有 Mirror 酱 CDK 可以直接使用此高速下载源

<RegionGate>

[Mirror 酱下载](https://mirrorchyan.com/zh/projects?rid=PCL2-CE&source=pcl2ce-web){.download-btn}

</RegionGate>

你也可以直接在下方的链接中下载

## 下载链接
Expand Down
4 changes: 4 additions & 0 deletions src/en/download.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ By clicking any download button below and running the program, you agree to our

If you have a MirrorChyan CDK, you can use this high-speed download source directly

<RegionGate>

[MirrorChyan Download](https://mirrorchyan.com/en/projects?rid=PCL2-CE&source=pcl2ce-gh-release){.download-btn}

</RegionGate>

You can also download directly from the links below

## Download Links
Expand Down
Loading