fixes: various bits fixed / improved based on fedback

This commit is contained in:
Starystars67
2025-12-29 16:16:17 +00:00
parent 31a179bc45
commit 6ed1bf7352
10 changed files with 198 additions and 51 deletions

12
package-lock.json generated
View File

@@ -1,19 +1,19 @@
{
"name": "beammp-website",
"version": "2.0.0",
"version": "2.4.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "beammp-website",
"version": "2.0.0",
"version": "2.4.7",
"dependencies": {
"@tailwindcss/vite": "^4.1.17",
"@vueuse/core": "^14.1.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.555.0",
"reka-ui": "^2.6.0",
"reka-ui": "^2.7.0",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tailwindcss-animate": "^1.0.7",
@@ -2832,9 +2832,9 @@
}
},
"node_modules/reka-ui": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.6.0.tgz",
"integrity": "sha512-NrGMKrABD97l890mFS3TNUzB0BLUfbL3hh0NjcJRIUSUljb288bx3Mzo31nOyUcdiiW0HqFGXJwyCBh9cWgb0w==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.7.0.tgz",
"integrity": "sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==",
"dependencies": {
"@floating-ui/dom": "^1.6.13",
"@floating-ui/vue": "^1.1.6",

View File

@@ -1,7 +1,7 @@
{
"name": "beammp-website",
"private": true,
"version": "2.4.7",
"version": "2.4.8",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,7 +16,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.555.0",
"reka-ui": "^2.6.0",
"reka-ui": "^2.7.0",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tailwindcss-animate": "^1.0.7",

View File

@@ -1,6 +1,14 @@
<script setup>
import { Github, Facebook, Instagram, createLucideIcon } from 'lucide-vue-next'
import { RouterLink } from 'vue-router'
import { getLocalizedPath } from '@/utils/locale'
import { RouterLink, useRoute } from 'vue-router'
const route = useRoute()
// Generate localized route
function localRoute(path) {
return getLocalizedPath(path, route.params.locale)
}
const XIcon = createLucideIcon('X', [
[
@@ -183,7 +191,7 @@ const TikTokIcon = createLucideIcon('TikTok', [
<p>&copy; 2019 - {{ new Date().getFullYear() }} | BeamMP Mod Team All Rights Reserved</p>
<div class="flex gap-3">
<RouterLink
to="/about"
:to="localRoute('about')"
class="text-neutral-700 hover:text-beammp-blue transition-colors dark:text-neutral-500 dark:hover:text-blue-400"
>
{{ $t('message.footer.about') }}

View File

@@ -33,31 +33,30 @@ function localRoute(path) {
<template>
<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"
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"
>
<nav class="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between">
<nav class="max-w-7xl mx-auto px-3 sm:px-4 h-16 flex items-center justify-between gap-2 sm:gap-4">
<RouterLink
:to="localRoute('')"
class="flex items-center gap-2 shrink-0"
class="flex items-center gap-2 flex-shrink-0"
@click="closeMobileMenu"
>
<!-- Light mode logo (black) -->
<img
src="/src/assets/BeamMP_blk.png"
alt="BeamMP Logo"
class="h-16 w-auto shrink-0 dark:hidden"
class="h-12 sm:h-14 w-auto flex-shrink-0 dark:hidden"
/>
<!-- Dark mode logo (white) -->
<img
src="/src/assets/BeamMP_wht.png"
alt="BeamMP Logo"
class="h-16 w-auto shrink-0 hidden dark:block"
class="h-12 sm:h-14 w-auto flex-shrink-0 hidden dark:block"
/>
</RouterLink>
<!-- Desktop Navigation -->
<!-- Switch to mobile earlier (avoid logo crowding) -->
<div class="hidden lg:flex items-center gap-4">
<div class="hidden xl:flex items-center gap-1 flex-1 justify-end overflow-x-auto">
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
@@ -194,14 +193,14 @@ function localRoute(path) {
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
<div class="flex items-center gap-2">
<div class="flex items-center gap-1 sm:gap-2 flex-shrink-0">
<LanguageSelector />
<ThemeToggle />
</div>
</div>
<!-- Mobile Menu Button and Theme Toggle -->
<div class="flex lg:hidden items-center gap-2">
<div class="flex xl:hidden items-center gap-1 sm:gap-2 flex-shrink-0">
<LanguageSelector />
<ThemeToggle />
<button
@@ -226,7 +225,7 @@ function localRoute(path) {
>
<div
v-if="mobileMenuOpen"
class="md:hidden border-t border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900"
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
@@ -275,6 +274,15 @@ function localRoute(path) {
>
{{ $t('message.nav.docs') }}
</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
href="https://github.com/BeamMP/BeamMP"
target="_blank"

View File

@@ -0,0 +1,42 @@
<script setup>
import { reactiveOmit } from "@vueuse/core";
import { Check } from "lucide-vue-next";
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from "reka-ui";
import { cn } from "@/lib/utils";
const props = defineProps({
defaultValue: { type: [Boolean, String], required: false },
modelValue: { type: [Boolean, String, null], required: false },
disabled: { type: Boolean, required: false },
value: { type: null, required: false },
id: { type: String, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
name: { type: String, required: false },
required: { type: Boolean, required: false },
class: { type: null, required: false },
});
const emits = defineEmits(["update:modelValue"]);
const delegatedProps = reactiveOmit(props, "class");
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<CheckboxRoot
v-bind="forwarded"
:class="
cn(
'grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
props.class,
)
"
>
<CheckboxIndicator class="grid place-content-center text-current">
<slot>
<Check class="h-4 w-4" />
</slot>
</CheckboxIndicator>
</CheckboxRoot>
</template>

View File

@@ -0,0 +1 @@
export { default as Checkbox } from "./Checkbox.vue";

View File

@@ -10,9 +10,10 @@
"forums": "Forums",
"docs": "Docs",
"communities": "Communities",
"partners": "Partners",
"partners": "Hosting Partners",
"servers": "Servers",
"statistics": "Statistics",
"store": "Merch Store",
"github": "GitHub",
"patreon": "Patreon",
"language": "Select Language",

View File

@@ -1,7 +1,8 @@
<script setup>
import { computed } from 'vue'
import { ExternalLink, Users, Trophy, Gamepad2, Shield, MapPin } from 'lucide-vue-next'
const communities = [
const communities = computed(() => [
{
name: 'BeamMP Racing League',
description:
@@ -121,7 +122,7 @@ const communities = [
},
color: 'from-amber-600 to-yellow-600',
},
]
])
</script>
<template>
@@ -250,7 +251,7 @@ const communities = [
<!-- CTA Section -->
<section class="text-center py-16 bg-neutral-50 dark:bg-neutral-900/30 -mx-4 px-4 rounded-xl">
<div class="max-w-2xl mx-auto space-y-6">
<h2 class="text-3xl md:text-4xl font-bold">{{ $t('message.communities.starting') }}</h2>
<h2 class="text-3xl md:text-4xl font-bold">{{ $t('message.communities.starting.title') }}</h2>
<p class="text-lg text-neutral-600 dark:text-neutral-400">
{{ $t('message.communities.starting.description') }}
</p>

View File

@@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted } from 'vue'
import { ref, computed, onMounted } from 'vue'
import {
Download,
Zap,
@@ -38,7 +38,7 @@ onMounted(async () => {
}
})
const features = [
const features = computed(() => [
{
icon: Server,
title: t('message.home.features.stable_servers.title'),
@@ -59,9 +59,9 @@ const features = [
title: t('message.home.features.sync.title'),
description: t('message.home.features.sync.description'),
},
]
])
const communities = [
const communities = computed(() => [
{
name: t('message.home.communities.racing.name'),
icon: Rocket,
@@ -86,9 +86,9 @@ const communities = [
description: t('message.home.communities.freeroam.description'),
color: 'from-green-500 to-emerald-500',
},
]
])
const devFeatures = [
const devFeatures = computed(() => [
{
icon: Code,
title: t('message.home.devFeatures.lua.title'),
@@ -96,7 +96,7 @@ const devFeatures = [
link:
'https://docs.beammp.com/' +
// eslint-disable-next-line no-undef
(locale == 'en' ? '' : locale + '/') +
(locale.value == 'en' ? '' : locale.value + '/') +
'scripting/mod-reference/',
},
{
@@ -104,7 +104,7 @@ const devFeatures = [
title: t('message.home.devFeatures.docs.title'),
description: t('message.home.devFeatures.docs.description'),
// eslint-disable-next-line no-undef
link: 'https://docs.beammp.com' + (locale == 'en' ? '' : locale + '/'),
link: 'https://docs.beammp.com/' + (locale.value == 'en' ? '' : locale.value + '/'),
},
{
icon: Wrench,
@@ -112,14 +112,14 @@ const devFeatures = [
description: t('message.home.devFeatures.openSource.description'),
link: 'https://github.com/BeamMP',
},
]
])
const stats = [
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: '+' },
]
const faqs = [
])
const faqs = computed(() => [
{
question: t('message.home.faq["0"].question'),
answer: t('message.home.faq["0"].answer'),
@@ -144,7 +144,7 @@ const faqs = [
question: t('message.home.faq["5"].question'),
answer: t('message.home.faq["5"].answer'),
},
]
])
</script>
<template>

View File

@@ -463,15 +463,17 @@ function joinServer(server) {
}
.servers-filters {
background: var(--card-bg, #f9f9f9);
border: 1px solid var(--border-color, #e0e0e0);
border-radius: 8px;
padding: 20px;
background: var(--filters-bg);
border: 1px solid var(--filters-border);
border-radius: 12px;
padding: 24px;
margin-bottom: 30px;
box-shadow: var(--filters-shadow);
backdrop-filter: blur(10px);
}
.filter-group {
margin-bottom: 15px;
margin-bottom: 20px;
}
.filter-group:last-child {
@@ -482,30 +484,87 @@ function joinServer(server) {
width: 100%;
padding: 12px 16px;
font-size: 1rem;
border: 1px solid var(--border-color, #d0d0d0);
border-radius: 6px;
border: 2px solid var(--border-color, #e0e0e0);
border-radius: 8px;
background: var(--input-bg, #fff);
color: var(--text-color, #1a1a1a);
transition: border-color 0.2s;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
font-weight: 500;
}
.search-input:focus {
outline: none;
border-color: var(--primary-color, #5d9cec);
border-color: #ff6a00;
box-shadow: 0 0 0 3px rgba(255, 106, 0, 0.1);
}
.search-input::placeholder {
color: var(--placeholder-color, var(--text-muted, #999));
}
.filter-heading {
display: block;
margin-bottom: 12px;
font-size: 0.9rem;
font-weight: 600;
color: var(--text-color, #1a1a1a);
text-transform: uppercase;
letter-spacing: 0.5px;
opacity: 0.7;
}
.filter-label {
display: inline-flex;
align-items: center;
margin-right: 20px;
margin-right: 24px;
margin-bottom: 12px;
font-size: 0.95rem;
cursor: pointer;
color: var(--text-color, #1a1a1a);
font-weight: 500;
transition: all 0.2s ease;
}
.filter-label:hover {
color: #ff6a00;
}
.filter-label input[type='checkbox'] {
margin-right: 6px;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 20px;
height: 20px;
margin-right: 10px;
cursor: pointer;
border: 2px solid var(--checkbox-border, #d0d0d0);
border-radius: 6px;
background: var(--checkbox-bg, #fff);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
flex-shrink: 0;
position: relative;
}
.filter-label input[type='checkbox']:hover {
border-color: #ff6a00;
box-shadow: 0 0 0 3px var(--checkbox-hover-shadow, rgba(255, 106, 0, 0.1));
}
.filter-label input[type='checkbox']:checked {
background: linear-gradient(135deg, #ff6a00 0%, #ff8c26 100%);
border-color: #ff6a00;
box-shadow: 0 2px 8px rgba(255, 106, 0, 0.3);
}
.filter-label input[type='checkbox']:checked::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-weight: bold;
font-size: 12px;
}
.server-count {
@@ -894,20 +953,27 @@ function joinServer(server) {
color: var(--text-muted, #666);
}
/* Dark mode support */
:global(.dark) .servers-container,
@media (prefers-color-scheme: dark) {
.servers-container {
--text-color: #e0e0e0;
--text-muted: #999;
--text-muted: #999999;
--card-bg: #2a2a2a;
--border-color: #404040;
--input-bg: #1a1a1a;
--tag-bg: #404040;
--primary-color: #5d9cec;
--header-bg: #1f1f1f;
--hover-bg: #333;
--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;
}
}
@@ -963,3 +1029,23 @@ 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);