mirror of
https://github.com/BeamMP/BeamMP-Website.git
synced 2026-02-16 02:30:47 +00:00
add GH release points to timeline & fix padding of nav and logo
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "beammp-website",
|
"name": "beammp-website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.4.8",
|
"version": "2.4.9",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -33,30 +33,31 @@ function localRoute(path) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header
|
<header
|
||||||
class="border-b border-neutral-200 dark:border-neutral-800 bg-white/80 dark:bg-neutral-900/70 backdrop-blur sticky top-0 z-20 overflow-hidden"
|
class="border-b border-neutral-200 dark:border-neutral-800 bg-white/80 dark:bg-neutral-900/70 backdrop-blur sticky top-0 z-20"
|
||||||
>
|
>
|
||||||
<nav class="max-w-7xl mx-auto px-3 sm:px-4 h-16 flex items-center justify-between gap-2 sm:gap-4">
|
<nav class="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between">
|
||||||
<RouterLink
|
<RouterLink
|
||||||
:to="localRoute('')"
|
:to="localRoute('')"
|
||||||
class="flex items-center gap-2 flex-shrink-0"
|
class="flex items-center gap-2 shrink-0 mr-4"
|
||||||
@click="closeMobileMenu"
|
@click="closeMobileMenu"
|
||||||
>
|
>
|
||||||
<!-- Light mode logo (black) -->
|
<!-- Light mode logo (black) -->
|
||||||
<img
|
<img
|
||||||
src="/src/assets/BeamMP_blk.png"
|
src="/src/assets/BeamMP_blk.png"
|
||||||
alt="BeamMP Logo"
|
alt="BeamMP Logo"
|
||||||
class="h-12 sm:h-14 w-auto flex-shrink-0 dark:hidden"
|
class="h-16 w-auto shrink-0 dark:hidden"
|
||||||
/>
|
/>
|
||||||
<!-- Dark mode logo (white) -->
|
<!-- Dark mode logo (white) -->
|
||||||
<img
|
<img
|
||||||
src="/src/assets/BeamMP_wht.png"
|
src="/src/assets/BeamMP_wht.png"
|
||||||
alt="BeamMP Logo"
|
alt="BeamMP Logo"
|
||||||
class="h-12 sm:h-14 w-auto flex-shrink-0 hidden dark:block"
|
class="h-16 w-auto shrink-0 hidden dark:block"
|
||||||
/>
|
/>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
<!-- Desktop Navigation -->
|
<!-- Desktop Navigation -->
|
||||||
<div class="hidden xl:flex items-center gap-1 flex-1 justify-end overflow-x-auto">
|
<!-- Switch to mobile earlier (avoid logo crowding) -->
|
||||||
|
<div class="hidden xl:flex items-center gap-4">
|
||||||
<NavigationMenu>
|
<NavigationMenu>
|
||||||
<NavigationMenuList>
|
<NavigationMenuList>
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
@@ -155,6 +156,24 @@ function localRoute(path) {
|
|||||||
</a>
|
</a>
|
||||||
</NavigationMenuLink>
|
</NavigationMenuLink>
|
||||||
</NavigationMenuItem>
|
</NavigationMenuItem>
|
||||||
|
<NavigationMenuItem>
|
||||||
|
<NavigationMenuLink as-child>
|
||||||
|
<a
|
||||||
|
href="https://store.beammp.com"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="External link"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
navigationMenuTriggerStyle(),
|
||||||
|
'bg-transparent text-neutral-900 hover:bg-neutral-100 hover:text-neutral-900 dark:bg-transparent dark:text-white dark:hover:bg-neutral-800 dark:hover:text-white'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ $t('message.nav.store') }}
|
||||||
|
</a>
|
||||||
|
</NavigationMenuLink>
|
||||||
|
</NavigationMenuItem>
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<NavigationMenuLink as-child>
|
<NavigationMenuLink as-child>
|
||||||
<a
|
<a
|
||||||
@@ -200,7 +219,7 @@ function localRoute(path) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile Menu Button and Theme Toggle -->
|
<!-- Mobile Menu Button and Theme Toggle -->
|
||||||
<div class="flex xl:hidden items-center gap-1 sm:gap-2 flex-shrink-0">
|
<div class="flex xl:hidden items-center gap-2">
|
||||||
<LanguageSelector />
|
<LanguageSelector />
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
<button
|
<button
|
||||||
@@ -225,7 +244,7 @@ function localRoute(path) {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="mobileMenuOpen"
|
v-if="mobileMenuOpen"
|
||||||
class="xl:hidden border-t border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900"
|
class="md: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">
|
<div class="px-4 py-3 space-y-1">
|
||||||
<RouterLink
|
<RouterLink
|
||||||
@@ -274,15 +293,6 @@ function localRoute(path) {
|
|||||||
>
|
>
|
||||||
{{ $t('message.nav.docs') }}
|
{{ $t('message.nav.docs') }}
|
||||||
</a>
|
</a>
|
||||||
<a
|
|
||||||
href="https://store.beammp.com"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
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.store') }}
|
|
||||||
</a>
|
|
||||||
<a
|
<a
|
||||||
href="https://github.com/BeamMP/BeamMP"
|
href="https://github.com/BeamMP/BeamMP"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ const servers = ref([])
|
|||||||
|
|
||||||
// Backend endpoints (use null to fall back to synthetic data)
|
// Backend endpoints (use null to fall back to synthetic data)
|
||||||
const STATS_ENDPOINT = null // e.g., 'https://backend.beammp.com/stats-timeseries'
|
const STATS_ENDPOINT = null // e.g., 'https://backend.beammp.com/stats-timeseries'
|
||||||
|
const MOD_RELEASES_ENDPOINT = 'https://api.github.com/repos/BeamMP/BeamMP/releases' // e.g., 'https://backend.beammp.com/releases'
|
||||||
|
const SERVER_RELEASES_ENDPOINT = 'https://api.github.com/repos/BeamMP/BeamMP-Server/releases' // e.g., 'https://backend.beammp.com/server-releases'
|
||||||
|
|
||||||
// All-time high tracking
|
// All-time high tracking
|
||||||
const peakPlayers = ref(0)
|
const peakPlayers = ref(0)
|
||||||
@@ -33,14 +35,52 @@ const selectedRangeKey = ref('7d')
|
|||||||
const selectedRange = computed(() => ranges.find((r) => r.key === selectedRangeKey.value))
|
const selectedRange = computed(() => ranges.find((r) => r.key === selectedRangeKey.value))
|
||||||
|
|
||||||
// Release markers (fill with real dates/labels as desired)
|
// Release markers (fill with real dates/labels as desired)
|
||||||
const releases = ref([
|
const mod_releases = ref([
|
||||||
{ date: '2025-11-24', label: 'v4.0.0' },
|
//{ date: '2025-11-24', label: 'v4.0.0' },
|
||||||
{ date: '2025-11-27', label: 'v4.1.0' },
|
//{ date: '2025-11-27', label: 'v4.1.0' },
|
||||||
{ date: '2025-11-29', label: 'v4.2.0' },
|
//{ date: '2025-11-29', label: 'v4.2.0' },
|
||||||
|
])
|
||||||
|
|
||||||
|
const server_releases = ref([
|
||||||
|
//{ date: '2025-11-25', label: 'v4.0.0' },
|
||||||
|
//{ date: '2025-11-28', label: 'v4.1.0' },
|
||||||
|
//{ date: '2025-11-30', label: 'v4.2.0' },
|
||||||
])
|
])
|
||||||
|
|
||||||
// Load time-series from backend or generate synthetic
|
// Load time-series from backend or generate synthetic
|
||||||
async function loadTimeSeries(points, stepHours) {
|
async function loadTimeSeries(points, stepHours) {
|
||||||
|
if (MOD_RELEASES_ENDPOINT) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(MOD_RELEASES_ENDPOINT)
|
||||||
|
if (res.ok) {
|
||||||
|
const r = await res.json()
|
||||||
|
r.forEach((rel) => {
|
||||||
|
const existing = mod_releases.value.find((e) => e.label === rel.tag_name)
|
||||||
|
if (!existing) {
|
||||||
|
mod_releases.value.push({ date: rel.published_at, label: rel.tag_name })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load releases:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SERVER_RELEASES_ENDPOINT) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(SERVER_RELEASES_ENDPOINT)
|
||||||
|
if (res.ok) {
|
||||||
|
const r = await res.json()
|
||||||
|
r.forEach((rel) => {
|
||||||
|
const existing = server_releases.value.find((e) => e.label === rel.tag_name)
|
||||||
|
if (!existing) {
|
||||||
|
server_releases.value.push({ date: rel.published_at, label: rel.tag_name })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load releases:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (STATS_ENDPOINT) {
|
if (STATS_ENDPOINT) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(STATS_ENDPOINT)
|
const res = await fetch(STATS_ENDPOINT)
|
||||||
@@ -256,7 +296,7 @@ function drawPlayers() {
|
|||||||
ctx.strokeStyle = 'rgba(255,106,0,0.8)'
|
ctx.strokeStyle = 'rgba(255,106,0,0.8)'
|
||||||
ctx.fillStyle = 'rgba(255,106,0,0.9)'
|
ctx.fillStyle = 'rgba(255,106,0,0.9)'
|
||||||
ctx.lineWidth = 1
|
ctx.lineWidth = 1
|
||||||
const rels = (releases.value || [])
|
const rels = (mod_releases.value || [])
|
||||||
.map((r) => ({ ...r, time: new Date(r.date).getTime() }))
|
.map((r) => ({ ...r, time: new Date(r.date).getTime() }))
|
||||||
.filter((r) => !isNaN(r.time) && r.time >= minT && r.time <= maxT)
|
.filter((r) => !isNaN(r.time) && r.time >= minT && r.time <= maxT)
|
||||||
releaseMarkersPlayers = []
|
releaseMarkersPlayers = []
|
||||||
@@ -380,7 +420,7 @@ function drawServers() {
|
|||||||
ctx.strokeStyle = 'rgba(255,106,0,0.8)'
|
ctx.strokeStyle = 'rgba(255,106,0,0.8)'
|
||||||
ctx.fillStyle = 'rgba(255,106,0,0.9)'
|
ctx.fillStyle = 'rgba(255,106,0,0.9)'
|
||||||
ctx.lineWidth = 1
|
ctx.lineWidth = 1
|
||||||
const rels = (releases.value || [])
|
const rels = (server_releases.value || [])
|
||||||
.map((r) => ({ ...r, time: new Date(r.date).getTime() }))
|
.map((r) => ({ ...r, time: new Date(r.date).getTime() }))
|
||||||
.filter((r) => !isNaN(r.time) && r.time >= minT && r.time <= maxT)
|
.filter((r) => !isNaN(r.time) && r.time >= minT && r.time <= maxT)
|
||||||
releaseMarkersServers = []
|
releaseMarkersServers = []
|
||||||
|
|||||||
Reference in New Issue
Block a user