mirror of
https://github.com/BeamMP/BeamMP-Website.git
synced 2026-02-16 02:30:47 +00:00
fixes: various bits fixed / improved based on fedback
This commit is contained in:
12
package-lock.json
generated
12
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>© 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') }}
|
||||
|
||||
@@ -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"
|
||||
|
||||
42
src/components/ui/checkbox/Checkbox.vue
Normal file
42
src/components/ui/checkbox/Checkbox.vue
Normal 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>
|
||||
1
src/components/ui/checkbox/index.js
Normal file
1
src/components/ui/checkbox/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Checkbox } from "./Checkbox.vue";
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user