mirror of
https://github.com/BeamMP/BeamMP-Website.git
synced 2026-07-13 02:04:47 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74adf15820 | |||
| 19cbd9da15 | |||
| c7db28166f | |||
| 8fa3ed49be | |||
| 33764c3ede | |||
| 017c8708d8 | |||
| d2ec932153 | |||
| 38213e1a50 | |||
| d879a2995f | |||
| c2e37eea5a | |||
| 13e36d5bc3 | |||
| b2cbc7239b | |||
| f203dfcbf5 | |||
| 58540763d2 | |||
| 1b9d2a0b87 | |||
| fa3059c09e | |||
| 7a840ac233 | |||
| 0322221529 | |||
| 9066e31c55 | |||
| d19a10c08b | |||
| a90e60ef32 | |||
| 070fb38709 | |||
| ed1cb0e2a8 | |||
| bedcd0cb50 | |||
| 2987de52ec | |||
| aaf888f182 | |||
| 052da9316c | |||
| 842e229e55 | |||
| b2742428d0 | |||
| 48717eeabd | |||
| 5f14414055 | |||
| a253919575 | |||
| 4626a69185 | |||
| 44268d076d | |||
| c2e460b408 | |||
| c827c81d28 | |||
| 5f9aad80ac | |||
| be9bae93de | |||
| 5295ec664b | |||
| f59b5df887 | |||
| cf3c3790b5 | |||
| d24ec58185 | |||
| a3f47c5b12 | |||
| d5c33e56e5 | |||
| 266c1470ba | |||
| 6fcf1d1f6f | |||
| 30eb6b96e0 | |||
| ebb7611a92 | |||
| 77c71a501f | |||
| c5988f94b0 | |||
| d1150ed84d | |||
| 5dfb7b79d7 | |||
| 19abd94069 | |||
| c0f96b35de | |||
| dedc16fb73 | |||
| f8d4478d35 | |||
| 738721119e | |||
| b8a5db6d48 | |||
| cc48fe2ffc | |||
| a307a3cd9f | |||
| 9a2a10499d | |||
| 3daa559a67 | |||
| e459538f18 | |||
| 0065093ca3 | |||
| 391f634d65 | |||
| 838a33b4d5 | |||
| 647ab8bda9 | |||
| 8b37e854d8 | |||
| 23ec17460e |
@@ -1,14 +1,12 @@
|
||||
name: Build Docker image and push to release
|
||||
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
if: 'github.event.release'
|
||||
if: "!github.event.release.prerelease"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Connect to Tailscale
|
||||
@@ -17,11 +15,6 @@ jobs:
|
||||
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
|
||||
tags: tag:ci
|
||||
- name: Install registry CA certificate
|
||||
run: |
|
||||
sudo mkdir -p /etc/docker/certs.d/${{ secrets.REGISTRY_URL }}
|
||||
echo "${{ secrets.REGISTRY_CA_CERT }}" | base64 -d | sudo tee /etc/docker/certs.d/${{ secrets.REGISTRY_URL }}/ca.crt
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
@@ -38,4 +31,4 @@ jobs:
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
push: true
|
||||
tags: ${{ secrets.REGISTRY_URL }}/beammp/website:${{ github.REF_NAME }}, ${{ secrets.REGISTRY_URL }}/beammp/website:prod
|
||||
tags: ${{ secrets.REGISTRY_URL }}/beammp/website:${{ github.REF_NAME }}, ${{ secrets.REGISTRY_URL }}/beammp/website:latest, ${{ secrets.REGISTRY_URL }}/beammp/website:production
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
name: Build Docker image and push to release
|
||||
name: Build Docker image and push to prerelease
|
||||
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
if: 'github.event.prerelease'
|
||||
if: github.event.release.prerelease
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Connect to Tailscale
|
||||
@@ -17,11 +15,6 @@ jobs:
|
||||
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
|
||||
tags: tag:ci
|
||||
- name: Install registry CA certificate
|
||||
run: |
|
||||
sudo mkdir -p /etc/docker/certs.d/${{ secrets.REGISTRY_URL }}
|
||||
echo "${{ secrets.REGISTRY_CA_CERT }}" | base64 -d | sudo tee /etc/docker/certs.d/${{ secrets.REGISTRY_URL }}/ca.crt
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
@@ -38,4 +31,4 @@ jobs:
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
push: true
|
||||
tags: ${{ secrets.REGISTRY_URL }}/beammp/website:${{ github.REF_NAME }}, ${{ secrets.REGISTRY_URL }}/beammp/website:dev
|
||||
tags: ${{ secrets.REGISTRY_URL }}/beammp/website:${{ github.REF_NAME }}, ${{ secrets.REGISTRY_URL }}/beammp/website:latest
|
||||
|
||||
+1
-1
@@ -102,7 +102,6 @@ dist
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
*.exe
|
||||
*.zip
|
||||
|
||||
# Logs
|
||||
@@ -129,3 +128,4 @@ frontend/*.ntvs*
|
||||
frontend/*.njsproj
|
||||
frontend/*.sln
|
||||
frontend/*.sw?
|
||||
.DS_Store
|
||||
|
||||
+11
-4
@@ -1,22 +1,29 @@
|
||||
# Step 1: Build stage
|
||||
FROM node:22-alpine3.21 AS build
|
||||
FROM node:lts-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
ENV NODE_ENV=development
|
||||
ENV NODE_ENV=production
|
||||
RUN npm run build
|
||||
|
||||
# Step 2: Serve stage
|
||||
FROM nginx:alpine
|
||||
FROM nginx:stable
|
||||
|
||||
# Remove default nginx static assets
|
||||
RUN rm -rf /usr/share/nginx/html/*
|
||||
|
||||
# Copy built files from the previous stage
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Add a custom Nginx configuration
|
||||
# Copy secure nginx configs
|
||||
COPY nginx.main.conf /etc/nginx/nginx.conf
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Use non-root user for security
|
||||
USER nginx
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
website:
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
container_name: website
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3000:80"
|
||||
+33
-8
@@ -2,21 +2,46 @@ server {
|
||||
listen 80;
|
||||
|
||||
server_name _;
|
||||
server_tokens off;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
# SPA fallback: serve index.html for non-file routes so Vue Router can render NotFound
|
||||
try_files $uri $uri/ /index.html;
|
||||
# Baseline security hardening for a static SPA.
|
||||
# NOTE: add_header directives are NOT inherited by child location blocks that
|
||||
# define their own add_header. To avoid silently dropping security headers,
|
||||
# use the `expires` directive (not add_header Cache-Control) in location blocks.
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: https:; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self' https://backend.beammp.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" always;
|
||||
|
||||
# Installer directory: serve files directly; return 404 for anything missing.
|
||||
location ^~ /installer/ {
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# Let real 404s for assets return 404s; Vue handles route-level 404 via the SPA fallback above.
|
||||
|
||||
location /static/ {
|
||||
# Serve static files directly
|
||||
expires max;
|
||||
# Vite-hashed assets (JS, CSS, fonts, images): serve directly with a long cache.
|
||||
# These files have content hashes in their names so stale cache is never an issue.
|
||||
# Return 404 if a file is genuinely missing rather than silently serving index.html.
|
||||
location ~* \.(js|css|woff2?|ttf|eot|svg|webp|avif|png|jpg|jpeg|gif|ico|map)$ {
|
||||
try_files $uri =404;
|
||||
expires 1y;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Data / download files: serve directly, no client-side cache, 404 if missing.
|
||||
location ~* \.(json|txt|exe|zip)$ {
|
||||
try_files $uri =404;
|
||||
expires -1;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# SPA fallback: all other paths go to index.html so Vue Router can render the
|
||||
# correct view (including the NotFound page for unknown routes).
|
||||
location / {
|
||||
try_files $uri /index.html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
error_log /tmp/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /tmp/access.log;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
server_tokens off;
|
||||
|
||||
# Redefine temp paths to writable tmpfs locations
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
proxy_temp_path /tmp/proxy_temp;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
Generated
+566
-503
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beammp-website",
|
||||
"private": true,
|
||||
"version": "2.4.15",
|
||||
"version": "2.4.24",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -33,6 +33,6 @@
|
||||
"eslint-plugin-vue": "^10.6.2",
|
||||
"prettier": "^3.7.3",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"vite": "^7.2.4"
|
||||
"vite": "^8.0.16"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 365 KiB |
+10
-16
@@ -1,10 +1,4 @@
|
||||
[
|
||||
{
|
||||
"name": "Horizon Hosting",
|
||||
"website": "https://hrzn.link/beammp",
|
||||
"from": "$3.34/mo",
|
||||
"logo": "https://hrznhosting.com/assets/logo.svg"
|
||||
},
|
||||
{
|
||||
"name": "RackGenius",
|
||||
"website": "https://rackgeni.us/beammp-plans",
|
||||
@@ -15,7 +9,7 @@
|
||||
"name": "Connect Hosting",
|
||||
"website": "https://connecthosting.net/beammp",
|
||||
"from": "$1.49/mo",
|
||||
"logo": "https://connecthosting.net/img/logo.webp"
|
||||
"logo": "https://connecthosting.net/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "Assetto Hosting",
|
||||
@@ -31,7 +25,7 @@
|
||||
},
|
||||
{
|
||||
"name": "HostHavoc",
|
||||
"website": "https://hosthavoc.com",
|
||||
"website": "https://hosthavoc.com/game-servers/beammp",
|
||||
"from": "$3.75/mo",
|
||||
"logo": "https://hosthavoc.com/images/logo.svg"
|
||||
},
|
||||
@@ -48,23 +42,17 @@
|
||||
"logo": "https://vyperhosting.com/assets/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "BisecHosting",
|
||||
"name": "BisectHosting",
|
||||
"website": "https://bisecthosting.com/beammp-server-hosting",
|
||||
"from": "$5.99/mo",
|
||||
"logo": "https://www.bisecthosting.com/_ipx/q_100&s_140x46/images/logo-dark-theme.svg"
|
||||
},
|
||||
{
|
||||
"name": "Four Season Hosting",
|
||||
"name": "Four Seasons Hosting",
|
||||
"website": "https://fourseasonshosting.com",
|
||||
"from": "$3.00/mo",
|
||||
"logo": "https://fourseasonshosting.com/_next/image?url=%2Flogo.png&w=256&q=75"
|
||||
},
|
||||
{
|
||||
"name": "Vertuo Hosting",
|
||||
"website": "https://vertuohosting.com",
|
||||
"from": "$1.99/mo",
|
||||
"logo": "https://vertuohosting.com/assets/img/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "Winheberg",
|
||||
"website": "https://winheberg.fr/offres/gaming/beammp",
|
||||
@@ -82,5 +70,11 @@
|
||||
"website": "https://iceline-hosting.com/games/beammp",
|
||||
"from": "$3.64/mo",
|
||||
"logo": "https://iceline-hosting.com/_astro/logo.DTnWV5zL_157TDr.webp"
|
||||
},
|
||||
{
|
||||
"name": "TLS Servers-Studios",
|
||||
"website": "https://tlsservers.com/beammp",
|
||||
"from": "$2.00/mo",
|
||||
"logo": "/partner_logos/TLS_Servers-Studios.png"
|
||||
}
|
||||
]
|
||||
|
||||
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 16 MiB After Width: | Height: | Size: 16 MiB |
@@ -60,7 +60,7 @@ function localRoute(path) {
|
||||
<div class="hidden xl:flex items-center gap-4">
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<!--<NavigationMenuItem>
|
||||
<NavigationMenuLink as-child>
|
||||
<RouterLink
|
||||
:to="localRoute('communities')"
|
||||
@@ -74,7 +74,7 @@ function localRoute(path) {
|
||||
{{ $t('message.nav.communities') }}
|
||||
</RouterLink>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuItem>-->
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink as-child>
|
||||
<RouterLink
|
||||
@@ -105,7 +105,7 @@ function localRoute(path) {
|
||||
</RouterLink>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<!--<NavigationMenuItem>
|
||||
<NavigationMenuLink as-child>
|
||||
<RouterLink
|
||||
:to="localRoute('stats')"
|
||||
@@ -119,8 +119,8 @@ function localRoute(path) {
|
||||
{{ $t('message.nav.statistics') }}
|
||||
</RouterLink>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
</NavigationMenuItem>-->
|
||||
<!--<NavigationMenuItem>
|
||||
<NavigationMenuLink as-child>
|
||||
<a
|
||||
href="https://forum.beammp.com"
|
||||
@@ -137,7 +137,7 @@ function localRoute(path) {
|
||||
{{ $t('message.nav.forums') }}
|
||||
</a>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuItem>-->
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink as-child>
|
||||
<a
|
||||
@@ -247,13 +247,13 @@ function localRoute(path) {
|
||||
class="xl:hidden border-t border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900"
|
||||
>
|
||||
<div class="px-4 py-3 space-y-1">
|
||||
<RouterLink
|
||||
<!--<RouterLink
|
||||
:to="localRoute('communities')"
|
||||
class="block px-4 py-3 text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||
@click="closeMobileMenu"
|
||||
>
|
||||
{{ $t('message.nav.communities') }}
|
||||
</RouterLink>
|
||||
</RouterLink>-->
|
||||
<RouterLink
|
||||
:to="localRoute('partners')"
|
||||
class="block px-4 py-3 text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||
@@ -268,14 +268,14 @@ function localRoute(path) {
|
||||
>
|
||||
{{ $t('message.nav.servers') }}
|
||||
</RouterLink>
|
||||
<RouterLink
|
||||
<!--<RouterLink
|
||||
:to="localRoute('stats')"
|
||||
class="block px-4 py-3 text-neutral-900 dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-md transition-colors"
|
||||
@click="closeMobileMenu"
|
||||
>
|
||||
{{ $t('message.nav.statistics') }}
|
||||
</RouterLink>
|
||||
<a
|
||||
</RouterLink>-->
|
||||
<!--<a
|
||||
href="https://forum.beammp.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -283,7 +283,7 @@ function localRoute(path) {
|
||||
@click="closeMobileMenu"
|
||||
>
|
||||
{{ $t('message.nav.forums') }}
|
||||
</a>
|
||||
</a>-->
|
||||
<a
|
||||
href="https://docs.beammp.com"
|
||||
target="_blank"
|
||||
|
||||
@@ -37,6 +37,11 @@ const toggleDropdown = () => {
|
||||
isOpen.value = !isOpen.value
|
||||
}
|
||||
|
||||
const getFlagUrl = (flagName) => {
|
||||
//return new URL(`../assets/flags/${flagName}.png`, import.meta.url).href
|
||||
return `/flags/${flagName}.png`
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const saved = localStorage.getItem('lang') || getCurrentLocale()
|
||||
if (saved && saved !== locale.value) {
|
||||
@@ -60,7 +65,7 @@ onMounted(async () => {
|
||||
@click="toggleDropdown"
|
||||
>
|
||||
<img
|
||||
:src="`/flags/${currentLanguage().flag}.png`"
|
||||
:src="getFlagUrl(currentLanguage().flag)"
|
||||
:alt="currentLanguage().name"
|
||||
class="w-5 h-4 rounded-sm"
|
||||
/>
|
||||
@@ -85,7 +90,7 @@ onMounted(async () => {
|
||||
]"
|
||||
@click="selectLanguage(code)"
|
||||
>
|
||||
<img :src="`/flags/${lang.flag}.png`" :alt="lang.name" class="w-5 h-4 rounded-sm" />
|
||||
<img :src="getFlagUrl(lang.flag)" :alt="lang.name" class="w-5 h-4 rounded-sm" />
|
||||
<span>{{ lang.name }}</span>
|
||||
<span v-if="locale === code" class="ml-auto text-neutral-500">✓</span>
|
||||
</button>
|
||||
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
import { nextTick } from 'vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
export const SUPPORT_LOCALES = ['en', 'es', 'fr', 'de', 'it', 'ru']
|
||||
export const SUPPORT_LOCALES = ['en', 'es', 'fr', 'de', 'it', 'ru', 'zh']
|
||||
|
||||
export const LANGUAGES = {
|
||||
en: { name: 'English', code: 'en', flag: 'gb' },
|
||||
@@ -10,6 +10,7 @@ export const LANGUAGES = {
|
||||
de: { name: 'Deutsch', code: 'de', flag: 'de' },
|
||||
it: { name: 'Italiano', code: 'it', flag: 'it' },
|
||||
ru: { name: 'Русский', code: 'ru', flag: 'ru' },
|
||||
zh: { name: '中文', code: 'zh', flag: 'cn' },
|
||||
}
|
||||
|
||||
export function setupI18n(options = { locale: 'en' }) {
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
{
|
||||
"message": {
|
||||
"theme": {
|
||||
"light": "明亮模式",
|
||||
"dark": "黑暗模式",
|
||||
"system": "跟随系统"
|
||||
},
|
||||
"nav": {
|
||||
"home": "主页",
|
||||
"forums": "论坛",
|
||||
"docs": "文档",
|
||||
"communities": "社区",
|
||||
"partners": "托管合作伙伴",
|
||||
"servers": "服务器",
|
||||
"statistics": "统计",
|
||||
"store": "周边商店",
|
||||
"github": "GitHub",
|
||||
"patreon": "在 Patreon 上为我们捐献",
|
||||
"language": "选择语言",
|
||||
"theme": {
|
||||
"light": "明亮主题",
|
||||
"dark": "黑暗主题",
|
||||
"system": "跟随系统"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"support_on_patreon": "Patreon",
|
||||
"about": "关于我们",
|
||||
"privacy_policy": "隐私政策",
|
||||
"terms_conditions": "条款与细则"
|
||||
},
|
||||
"404": {
|
||||
"title": "找不到页面",
|
||||
"description": "此页面不存在,\n此页面可能不存在或已经被删除",
|
||||
"return_home": "返回首页"
|
||||
},
|
||||
"home": {
|
||||
"hero": {
|
||||
"title": "为BeamNG.Drive 提供多人游戏",
|
||||
"subtitle": "联机体验软体物理引擎\n和朋友一起赛车 角色扮演或闲逛",
|
||||
"download_now": "现在下载",
|
||||
"browse_servers": "查看服务器"
|
||||
},
|
||||
"metrics": {
|
||||
"active_players": "活跃玩家",
|
||||
"players_online": "在线玩家",
|
||||
"public_servers": "公开服务器",
|
||||
"all_servers": "所有服务器"
|
||||
},
|
||||
"why_beammp": "为什么选择BeamMP?",
|
||||
"features": {
|
||||
"stable_servers": {
|
||||
"title": "稳定",
|
||||
"description": "BeamMP在全球开设服务器 提供稳定体验"
|
||||
},
|
||||
"beamng": {
|
||||
"title": "易用",
|
||||
"description": "BeamMP与BeamNG使用相同的地图 车辆和模组 无需学习新东西"
|
||||
},
|
||||
"standalone": {
|
||||
"title": "独立",
|
||||
"description": "BeamMP不会修改你的BeamNG 你可以无缝使用单机和联机"
|
||||
},
|
||||
"sync": {
|
||||
"title": "流畅",
|
||||
"description": "BeamMP 每秒更新~50次同步 带来流畅的联机体验"
|
||||
}
|
||||
},
|
||||
"communities": {
|
||||
"join": "加入这个充满活力的社区",
|
||||
"description": "探索数千个独特服务器上的多样化游戏体验",
|
||||
"racing": {
|
||||
"name": "赛车",
|
||||
"description": "为全球玩家提供联机赛车与计时赛"
|
||||
},
|
||||
"roleplay": {
|
||||
"name": "角色扮演",
|
||||
"description": "从警匪追逐到货运模拟都能获得沉浸的体验"
|
||||
},
|
||||
"crash": {
|
||||
"name": "破坏",
|
||||
"description": "以德比和破坏为玩法的主题玩法"
|
||||
},
|
||||
"freeroam": {
|
||||
"name": "自由漫游与自定义服务器",
|
||||
"description": "探索开放世界服务器,或使用自定义脚本、地图和模组构建你自己的服务器。"
|
||||
}
|
||||
},
|
||||
"find": {
|
||||
"title": "寻找你的完美服务器",
|
||||
"description": "查看数百个活跃服务器 拥有不同的游戏模式 模组和社区 从竞速到休闲 每个人都能在这里找到适合自己的服务器",
|
||||
"points": {
|
||||
"custom": "独特体验",
|
||||
"custom_desc": "每个玩法都由社区创造",
|
||||
"moderation": "环境友好",
|
||||
"moderation_desc": "安全友好的游戏环境",
|
||||
"global": "极低延迟",
|
||||
"global_desc": "全球服务器实现低延迟"
|
||||
},
|
||||
"browse_all_servers": "浏览全部服务器"
|
||||
},
|
||||
"devFeatures": {
|
||||
"title": "为开发者而生",
|
||||
"description": "打造独特游戏规则 开设自己的服务器 为项目做出贡献",
|
||||
"lua": {
|
||||
"title": "Lua API",
|
||||
"description": "强大的服务器端Lua脚本支持,用于实现自定义游戏模式与功能。"
|
||||
},
|
||||
"docs": {
|
||||
"title": "文档",
|
||||
"description": "面向服务器开发的详尽指南与API参考文档"
|
||||
},
|
||||
"openSource": {
|
||||
"title": "开源",
|
||||
"description": "采用社区驱动开发模式,并在GitHub上开源"
|
||||
},
|
||||
"learn_more": "了解更多",
|
||||
"host": {
|
||||
"title": "准备搭建您的专属服务器了吗?",
|
||||
"description": "下载服务器文件,即可打造您独特的BeamMP游戏体验。",
|
||||
"windows": "Windows 服务器端",
|
||||
"linux": "Linux 服务器端",
|
||||
"partners": {
|
||||
"description": "通过我们可信赖的托管合作伙伴快速上手,享受无忧设置、24/7技术支持和优化性能。",
|
||||
"view_partners": "查看托管合作伙伴"
|
||||
},
|
||||
"self_host": {
|
||||
"title": "或者自托管"
|
||||
}
|
||||
}
|
||||
},
|
||||
"faq": {
|
||||
"title": "常见问题回答",
|
||||
"0": {
|
||||
"question": "服务器列表没有显示!",
|
||||
"answer": "如果遇到此问题,可尝试重启BeamMP客户端。若仍未解决,请在官方论坛发帖或加入Discord支持频道寻求帮助。"
|
||||
},
|
||||
"1": {
|
||||
"question": "若遇到问题或有疑问,如何提交工单?",
|
||||
"answer": "请查看Discord及官方论坛中的#how-to-use频道。详细描述您已尝试的操作步骤,以便支持团队能够快速有效地为您提供帮助。"
|
||||
},
|
||||
"2": {
|
||||
"question": "求助!我遇到错误代码了",
|
||||
"answer": "请前往我们的论坛查看是否有人遇到过相同问题。很可能已有其他用户遇到过类似情况,回复中通常也会附有解决方案。或者可以访问我们的Discord频道,那里是目前更活跃的社区,大家都很热心帮助。"
|
||||
},
|
||||
"3": {
|
||||
"question": "我可以在盗版的BeamNG.Drive上玩吗?",
|
||||
"answer": "我们尚不确定其是否兼容BeamNG.drive的盗版版本,但对于非正版游戏副本,我们将不提供任何技术支持,也不会兼容它"
|
||||
},
|
||||
"4": {
|
||||
"question": "如何托管服务器?",
|
||||
"answer": "托管服务器所需的文件可在本页顶部客户端下载下方找到。同时您需要在Keymaster获取认证密钥。更多设置相关信息请查阅我们的官方文档。"
|
||||
},
|
||||
"5": {
|
||||
"question": "我可以使用模组吗?",
|
||||
"answer": "模组是支持的,这些安装在服务器上。请查看我们的文档以获取更多信息。"
|
||||
}
|
||||
},
|
||||
"stats": {
|
||||
"active_players": "活跃玩家",
|
||||
"global_servers": "全球服务器",
|
||||
"total_downloads": "总下载量"
|
||||
}
|
||||
},
|
||||
"communities": {
|
||||
"title": "社区",
|
||||
"description": "发现围绕BeamMP建立的繁荣社区。从竞技赛车联盟到休闲自由漫游会话,找到您完美的玩伴群组。",
|
||||
"starting": {
|
||||
"title": "想要创建您自己的社区吗?",
|
||||
"description": "托管您自己的BeamMP服务器,并围绕您钟爱的游戏模式建立社区。",
|
||||
"setup_guide": "服务器设置指南",
|
||||
"join_discord": "加入我们的Discord"
|
||||
}
|
||||
},
|
||||
"partners": {
|
||||
"title": "托管合作伙伴",
|
||||
"description": "选择我们值得信赖的托管合作伙伴。简单的设置、优化的性能和支持,以确保您的BeamMP服务器运行顺畅。",
|
||||
"from_price": "从 {price}",
|
||||
"visit_website": "访问网站",
|
||||
"error_loading": "无法获取合作伙伴信息"
|
||||
},
|
||||
"servers": {
|
||||
"title": "服务器",
|
||||
"description": "探索并加入来自全球的BeamMP服务器。在此一站式发现您钟爱的游戏模式、活跃社群与丰富玩法。",
|
||||
"show_only": "仅显示:",
|
||||
"loading_servers": "加载服务器中...",
|
||||
"server_count": "0 个发现的服务器 | 1 个发现的服务器 | {count} 发现的服务器",
|
||||
"players_found": "0 个玩家 | 1 个玩家 | {count} 个玩家",
|
||||
"filters": {
|
||||
"hide_empty": "隐藏空服务器",
|
||||
"hide_full": "隐藏爆满服务器",
|
||||
"search": "搜索服务器中",
|
||||
"hide_password": "隐藏受密码保护的服务器",
|
||||
"show_official": "官方服务器",
|
||||
"show_partner": "合作伙伴服务器",
|
||||
"show_featured": "推荐服务器"
|
||||
},
|
||||
"table_headers": {
|
||||
"location": "位置",
|
||||
"name": "服务器名称",
|
||||
"map": "地图",
|
||||
"players": "玩家",
|
||||
"mods": "模组",
|
||||
"status": "状态"
|
||||
}
|
||||
},
|
||||
"statistics": {
|
||||
"title": "统计数据",
|
||||
"description": "提供活跃服务器的实时快照指标与玩家数量时间线。支持在图表上标注版本发布日期。",
|
||||
"loading": "加载中...",
|
||||
"peak": "峰值: {count}",
|
||||
"current_players": "当前玩家",
|
||||
"current_servers": "当前服务器",
|
||||
"avg_players_per_server": "服务器平均玩家数量",
|
||||
"official_servers": "官方服务器",
|
||||
"partner_servers": "合作伙伴服务器",
|
||||
"player_volume": "在线人数时间轴",
|
||||
"hint": "版本发布标记显示为橙色垂直虚线(例如 v3.0.0、v4.0.0)。悬停鼠标至数据点可查看详细信息。",
|
||||
"server_volume": "服务器数量时间轴",
|
||||
"server_hint": "服务器数量呈现相似趋势。发布标记指示主要版本发布。"
|
||||
},
|
||||
"about": {
|
||||
"title": "关于BeamMP",
|
||||
"description": "BeamMP可为BeamNG.drive带来多人游戏体验。它由社区共建、为社区服务,注重稳定性与性能,致力于让您与朋友共享真实的驾驶体验。",
|
||||
"note": {
|
||||
"title": "开发者的话",
|
||||
"content": "BeamMP 始于一个简单的想法:我想和我的兄弟们一起玩BeamNG.drive。这个最初作为实验的项目,迅速成长为一个社区驱动的倡议,专注于实现多人游戏体验与乐趣。我们深切关注于提供尽可能最佳的用户体验,并让玩家能够轻松加入,享受共同驾驶的快乐。该项目向所有技能水平的贡献者开放——无论您是编写代码、管理服务器、设计场景,还是帮助他人完成设置,您的努力都是 BeamMP 蓬勃发展的关键部分。感谢您的参与,帮助我们共同构建这个非凡的项目。"
|
||||
},
|
||||
"provides": {
|
||||
"title": "BeamMP的功能与服务",
|
||||
"points": {
|
||||
"0": "提供BeamNG.drive的多人联机会话,支持服务器浏览器与筛选功能。",
|
||||
"1": "服务器端管理工具与配置选项",
|
||||
"2": "模组支持与付费内容保护机制",
|
||||
"3": "活跃的社区(论坛、Discord),可以提供帮助与协作支持。"
|
||||
}
|
||||
},
|
||||
"project": {
|
||||
"title": "项目价值观",
|
||||
"points": {
|
||||
"0": "社区优先:决策由真实玩家/服务器需求引导",
|
||||
"1": "可靠性:我们始终把游戏稳定性、数据同步精度和性能表现放在首位,能优化到的地方都全力以赴。",
|
||||
"2": "开放:欢迎贡献、反馈与透明",
|
||||
"3": "安全:促进公平游戏和尊重互动"
|
||||
}
|
||||
},
|
||||
"get_involved": {
|
||||
"title": "参与进来",
|
||||
"description": "参与的方式有很多种——比如加入讨论、反馈问题、贡献代码,或者通过捐赠等途径给项目提供财务支持。",
|
||||
"patreon": "Patreon",
|
||||
"forum": "论坛",
|
||||
"docs": "文档",
|
||||
"github": "GitHub",
|
||||
"discord": "Discord"
|
||||
},
|
||||
"funding": {
|
||||
"title": "资金与可持续发展",
|
||||
"description": "BeamMP的发展离不开社区的支持。捐款将用于支付服务器等基础设施、带宽、工具及开发时间的成本。如果您认可本项目并愿意支持我们持续成长,请考虑为我们提供捐助。",
|
||||
"patreon": "在Patreon上支持我们",
|
||||
"learn": "了解更多内容请访问GitHub"
|
||||
},
|
||||
"credits": {
|
||||
"title": "致谢与贡献者",
|
||||
"description": "BeamMP项目由模组团队及一众优秀的社区贡献者共同维护。我们同时感谢所有服务器所有者、模组创作者、测试人员以及积极反馈问题的用户——你们的时间与热情是项目持续前进的动力。",
|
||||
"desc_2": "衷心感谢BeamNG.drive的开发团队,他们打造的卓越平台为多人游戏功能的实现奠定了坚实基础。",
|
||||
"desc_3": "同时衷心感谢以下现任与曾经的社区成员,感谢他们多年来对BeamMP项目作出的重大贡献:",
|
||||
"mentions": {
|
||||
"0": "Jojos38(联合创始人)—感谢他早期在设计各方面的工作,帮助将想法变为现实。",
|
||||
"1": "Jetta(jetta.cat)—负责标志的设计与制作。",
|
||||
"2": "Anonymous275 与 Lionkor — 在项目重构期间负责使用 C++ 重写代码的工作。",
|
||||
"3": "Tixx — 感谢他对整个项目代码库作出的重大贡献。",
|
||||
"4": "以及更多未列名的贡献者—衷心感谢每一位以各种方式支持过本项目的朋友!"
|
||||
},
|
||||
"thank_you": "我们正在共同打造一个独特的作品—真诚感谢您成为BeamMP社区的一员!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-6
@@ -14,13 +14,25 @@ import {
|
||||
Rocket,
|
||||
} from 'lucide-vue-next'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import landingLq from '@/assets/landing-lq.jpg'
|
||||
import landingHq from '@/assets/landing_hq.png'
|
||||
const { t } = useI18n()
|
||||
|
||||
const onlinePlayers = ref('...')
|
||||
const onlineServers = ref('...')
|
||||
const totalServers = ref('...')
|
||||
const isLoading = ref(true)
|
||||
const heroImageLoaded = ref(false)
|
||||
const heroImageSrc = ref('/landing-lq.jpg')
|
||||
const heroImageSrc = ref(landingLq)
|
||||
const installerDownloadUrl = computed(() => {
|
||||
const base = import.meta.env.BASE_URL || '/'
|
||||
if (base === './') {
|
||||
return '/installer/BeamMP_Installer.exe'
|
||||
}
|
||||
return `${base.replace(/\/$/, '')}/installer/BeamMP_Installer.exe`
|
||||
|
||||
//return 'https://github.com/BeamMP/BeamMP-Launcher/releases/download/v2.8.0/BeamMP_Installer.exe'
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
@@ -31,19 +43,21 @@ onMounted(async () => {
|
||||
if (values.length >= 2) {
|
||||
onlinePlayers.value = values[1]
|
||||
onlineServers.value = values[3]
|
||||
totalServers.value = values[5]
|
||||
}
|
||||
} catch {
|
||||
onlinePlayers.value = 'N/A'
|
||||
onlineServers.value = 'N/A'
|
||||
totalServers.value = 'N/A'
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
// Load high-quality hero image
|
||||
const img = new Image()
|
||||
img.src = '/landing_hq.png'
|
||||
img.src = landingHq
|
||||
img.onload = () => {
|
||||
heroImageSrc.value = '/landing_hq.png'
|
||||
heroImageSrc.value = landingHq
|
||||
heroImageLoaded.value = true
|
||||
}
|
||||
})
|
||||
@@ -126,8 +140,8 @@ const devFeatures = computed(() => [
|
||||
|
||||
const stats = computed(() => [
|
||||
{ label: t('message.home.metrics.active_players'), value: onlinePlayers, suffix: '+' },
|
||||
{ label: t('message.home.metrics.public_servers'), value: '500', suffix: '+' },
|
||||
{ label: t('message.home.metrics.all_servers'), value: '2M', suffix: '+' },
|
||||
{ label: t('message.home.metrics.public_servers'), value: onlineServers, suffix: '+' },
|
||||
{ label: t('message.home.metrics.all_servers'), value: totalServers, suffix: '+' },
|
||||
])
|
||||
const faqs = computed(() => [
|
||||
{
|
||||
@@ -188,7 +202,7 @@ const faqs = computed(() => [
|
||||
<!-- CTA Buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center items-center pt-4">
|
||||
<a
|
||||
href="/installer/BeamMP_Installer.zip"
|
||||
:href="installerDownloadUrl"
|
||||
download
|
||||
class="group flex items-center gap-3 bg-linear-to-r from-beammp-orange to-red-600 hover:from-red-600 hover:to-beammp-orange px-8 py-4 rounded-lg font-semibold text-lg transition-all transform hover:scale-105 shadow-lg hover:shadow-beammp-orange/50 text-white"
|
||||
>
|
||||
@@ -279,6 +293,7 @@ const faqs = computed(() => [
|
||||
</div>
|
||||
<div class="text-center mt-8">
|
||||
<RouterLink
|
||||
style="display: none;"
|
||||
:to="`/${$i18n.locale}/communities`"
|
||||
class="inline-flex items-center gap-2 bg-beammp-orange hover:bg-beammp-orange/90 text-white px-6 py-3 rounded-lg font-semibold transition-colors"
|
||||
>
|
||||
|
||||
+21
-44
@@ -244,8 +244,8 @@ const regionDisplay = computed(() => {
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const response = await fetch('/servers.json')
|
||||
//const response = await fetch('https://backend.beammp.com/servers-info')
|
||||
//const response = await fetch('/servers.json')
|
||||
const response = await fetch('https://backend.beammp.com/servers-info')
|
||||
console.log(response)
|
||||
if (!response.ok) throw new Error('Failed to fetch servers')
|
||||
const data = await response.json()
|
||||
@@ -945,28 +945,25 @@ function joinServer(server) {
|
||||
color: var(--text-muted, #666);
|
||||
}
|
||||
|
||||
:global(.dark) .servers-container,
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.servers-container {
|
||||
--text-color: #e0e0e0;
|
||||
--text-muted: #999999;
|
||||
--card-bg: #2a2a2a;
|
||||
--border-color: #404040;
|
||||
--input-bg: #1a1a1a;
|
||||
--tag-bg: #404040;
|
||||
--primary-color: #5d9cec;
|
||||
--header-bg: #1f1f1f;
|
||||
--hover-bg: #333333;
|
||||
--active-bg: #2a3f5f;
|
||||
--details-bg: #252525;
|
||||
--filters-bg: linear-gradient(135deg, rgba(30, 30, 30, 0.95) 0%, rgba(20, 20, 20, 0.98) 100%);
|
||||
--filters-border: rgba(255, 106, 0, 0.2);
|
||||
--filters-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
--checkbox-bg: rgba(255, 255, 255, 0.05);
|
||||
--checkbox-border: rgba(255, 255, 255, 0.15);
|
||||
--checkbox-hover-shadow: rgba(255, 106, 0, 0.15);
|
||||
--placeholder-color: #666666;
|
||||
}
|
||||
:global(.dark) .servers-container {
|
||||
--text-color: #e0e0e0;
|
||||
--text-muted: #999999;
|
||||
--card-bg: #2a2a2a;
|
||||
--border-color: #404040;
|
||||
--input-bg: #1a1a1a;
|
||||
--tag-bg: #404040;
|
||||
--primary-color: #5d9cec;
|
||||
--header-bg: #1f1f1f;
|
||||
--hover-bg: #333333;
|
||||
--active-bg: #2a3f5f;
|
||||
--details-bg: #252525;
|
||||
--filters-bg: linear-gradient(135deg, rgba(30, 30, 30, 0.95) 0%, rgba(20, 20, 20, 0.98) 100%);
|
||||
--filters-border: rgba(255, 106, 0, 0.2);
|
||||
--filters-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
--checkbox-bg: rgba(255, 255, 255, 0.05);
|
||||
--checkbox-border: rgba(255, 255, 255, 0.15);
|
||||
--checkbox-hover-shadow: rgba(255, 106, 0, 0.15);
|
||||
--placeholder-color: #666666;
|
||||
}
|
||||
|
||||
/* Mobile responsive */
|
||||
@@ -1013,23 +1010,3 @@ function joinServer(server) {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
/* Light theme defaults */
|
||||
--text-color: #1a1a1a;
|
||||
--text-muted: #666666;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e0e0e0;
|
||||
--input-bg: #ffffff;
|
||||
--tag-bg: #e8e8e8;
|
||||
--primary-color: #5d9cec;
|
||||
--header-bg: #f5f5f5;
|
||||
--hover-bg: #f9f9f9;
|
||||
--active-bg: #f0f7ff;
|
||||
--details-bg: #fafafa;
|
||||
--filters-bg: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(249, 249, 249, 0.95) 100%);
|
||||
--filters-border: var(--border-color, #e0e0e0);
|
||||
--filters-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
--checkbox-bg: #ffffff;
|
||||
--checkbox-border: #d0d0d0;
|
||||
--checkbox-hover-shadow: rgba(255, 106, 0, 0.1);
|
||||
--placeholder-color: var(--text-muted, #999999);
|
||||
|
||||
Reference in New Issue
Block a user