Compare commits

..
Author SHA1 Message Date
Starystars67 d80dc4dea0 Update index.html 2025-12-20 02:22:46 +00:00
Starystars67 04fb9ba50f stop x scroll.. 2025-12-20 02:16:32 +00:00
Starystars67 2d83ba9dfd fix height to match theme toggle 2025-12-20 02:13:41 +00:00
Starystars67 c0a10c4710 Fix socials and linux icon 2025-12-20 02:09:12 +00:00
Starystars67 1e8489018d missed detail 2025-12-20 01:42:52 +00:00
Starystars67 ab6c93791f Update package.json 2025-12-20 01:22:09 +00:00
Starystars67andTixx acc1377bbb Add initial templates for additional languages
Co-Authored-By: Tixx <83774803+WiserTixx@users.noreply.github.com>
2025-12-20 01:20:03 +00:00
Starystars67andTixx 3873388b48 Added i18n Translation Support
Co-Authored-By: Tixx <83774803+WiserTixx@users.noreply.github.com>
2025-12-20 00:28:36 +00:00
Starystars67 0d4d34634a put correct servers address. 2025-11-30 17:41:15 +00:00
Starystars67 d5b7c52641 various changes 2025-11-30 17:39:52 +00:00
Starystars67 9c85fb2f10 Add GH actions files. 2025-11-30 16:08:36 +00:00
Starystars67 a2d2cb07d4 adjust dockerfile 2025-11-30 16:04:00 +00:00
Starystars67 403489e43c Rebuild website! 2025-11-30 16:01:49 +00:00
Starystars67 1671b775e4 More bits of work 2024-10-22 19:10:46 +01:00
Starystars67 4d8c30f48c New navbar and updated logos & links 2024-10-22 16:57:42 +01:00
372 changed files with 80020 additions and 38630 deletions

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
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
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: registry.beammp.com/beammp/website:${{ github.ref_name }}
+30
View File
@@ -0,0 +1,30 @@
name: Build Docker image and push to staging
on:
push:
branches:
- "dev"
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to Docker Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: registry.beammp.com/beammp/website:staging
+6
View File
@@ -0,0 +1,6 @@
node_modules
dist
*.log
.DS_Store
pnpm-lock.yaml
package-lock.json
+11
View File
@@ -0,0 +1,11 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "es5",
"printWidth": 100,
"arrowParens": "always",
"endOfLine": "lf",
"vueIndentScriptAndStyle": false
}
+16 -18
View File
@@ -1,25 +1,23 @@
FROM node:18.16.0-alpine3.17 # Step 1: Build stage
FROM node:22-alpine3.21 AS build
# Create app directory
WORKDIR /app WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ENV NODE_ENV=development
RUN npm run build
RUN apk --no-cache add curl # Step 2: Serve stage
FROM nginx:alpine
# Install app dependencies # Copy built files from the previous stage
# A wildcard is used to ensure both package.json AND package-lock.json are copied COPY --from=build /app/dist /usr/share/nginx/html
# where available (npm@5+)
COPY package*.json /app
# General Install of Deps # Add a custom Nginx configuration
# RUN npm install COPY nginx.conf /etc/nginx/conf.d/default.conf
# If you are building your code for production
RUN npm ci --only=production
# Bundle app source # Expose port 80
COPY . /app EXPOSE 80
EXPOSE 3599 CMD ["nginx", "-g", "daemon off;"]
HEALTHCHECK CMD curl --fail http://localhost:3599/ping || exit 1
CMD [ "node", "index.js" ]
+129 -1
View File
@@ -1 +1,129 @@
# BeamMP-Website # BeamMP Website (Frontend)
This repository is home for the BeamMP website, this is a rebuild of the website from the ground up using Vue+Vite. We are also making use of Tailwindcss v4.
**Tech Stack**
- **Framework:** Vue 3 (`vue`, `vue-router`)
- **Build:** Vite 7 (`vite`, `@vitejs/plugin-vue`)
- **Styling:** Tailwind CSS 4 + `tailwindcss-animate`, `tailwind-merge`
- **UI Icons/Utils:** `lucide-vue-next`, `clsx`, `class-variance-authority`
- **Radix-style Components:** `reka-ui` through `shadcn-vue`
- **Composable utilities:** `@vueuse/core`
**Theming and Colour Guide**
- BeamMP Orange `#F36D24`
- BeamMP Blue `#4470B6`
- BeamMP Green `#1D9749`
- Gray `#333333`
- Black `#000000`
- White `#FFFFFF`
## Getting Started
Prerequisites:
- Node.js 22+
- pnpm, npm, or yarn (examples use npm)
Install dependencies and run the dev server:
```powershell
# from this folder (repo root)
npm install
npm run dev
```
Build for production and preview locally:
```powershell
npm run build
npm run preview
```
Vite will print the local dev URL (usually `http://localhost:5173`).
## Project Scripts
- `npm run dev`: Start Vite development server
- `npm run build`: Production build
- `npm run preview`: Preview the production build locally
- `npm run lint`: Lint and auto-fix Vue/JS files with ESLint
- `npm run format`: Format all source files with Prettier
## Directory Overview
- `src/` – App source (styles, components, pages, routing)
- `src/components/ui/` – UI components (e.g., `button`, `navigation-menu`)
- `src/lib/` – Utilities and helpers
- `routes/` - vue-router routes
- `views/` - Pages of the website
- `index.html` – Vite HTML entry
- `tailwind.config.js` – Tailwind configuration
- `vite.config.js` – Vite configuration
- `components.json` – Shadcn-Vue component registry
## Styling and UI
- **Tailwind CSS 4** is set up via `tailwind.config.js` and imported in `src/style.css`.
- **reka-ui** and shadcn-vue-style patterns are used for accessible, composable UI.
- **lucide-vue-next** provides icons.
## Adding New UI Components (shadcn-vue)
We’re standardizing on shadcn-vue-compatible components for consistency. Use the CLI to add new components:
```powershell
npx shadcn-vue@latest add <component>
# examples
npx shadcn-vue@latest add button
npx shadcn-vue@latest add navigation-menu
```
The CLI reads `components.json` and will scaffold files under `src/components/ui/`.
## Routing
Use `vue-router` for navigation. Keep routes co-located with views and prefer lazy-loaded routes for large pages.
## Contributing
We welcome contributions! Here’s how to get started.
### 1) Pick an Issue or Open One
- Browse issues or propose an enhancement/bug. Share context and repro steps.
### 2) Create a Branch
- Use a descriptive branch name:
- `feature/<short-description>`
- `fix/<short-description>`
- `docs/<short-description>`
### 3) Dev Environment
- Install deps with `npm install` and run `npm run dev`.
- Keep changes scoped and focused; avoid drive-by refactors unless agreed.
### 4) Code Style & Patterns
- **Vue 3 + `<script setup>`** preferred for new components.
- **Linting**: Run `npm run lint` before committing to catch errors. ESLint is configured for Vue 3 best practices.
- **Formatting**: Run `npm run format` to auto-format code with Prettier (or use an editor extension).
- **Type safety**: If/when TypeScript is introduced, prefer explicit props and emits.
- **Tailwind**: Use utility classes; extract variants with `class-variance-authority` when patterns repeat.
- **Accessibility**: Prefer accessible primitives (e.g., `reka-ui`) and keyboard support.
- **File naming**: `PascalCase.vue` for components; avoid one-letter variable names.
### 5) Testing & Checks
- Run the app locally and verify core flows.
- Ensure components render on both light/dark themes if relevant.
- If you add dependencies, update this README and relevant configs.
### 6) Commit & PR
- Write clear, imperative commit messages, e.g., `feat: add NavigationMenu component`.
- Open a PR describing the problem, solution, screenshots if UI changes, and any follow-ups.
- Link related issues. Keep PRs small; big changes should be split.
## Environment & Configuration
- Tailwind and Vite are preconfigured. If you need globals, add them in `vite.config.js`.
- For icons, use `lucide-vue-next` and keep icon size consistent via props/classes.
- If adding new pages, prefer code-splitting with dynamic imports.
## FAQ
- “Why Vite?” Fast dev server, optimized builds, and great Vue tooling.
- “Can I use Yarn or pnpm?” Yes—adjust commands accordingly.
- “Design system?” We favor shadcn-vue patterns + Tailwind + reka-ui primitives for consistent UI.
## License
Unless otherwise noted in the root repository, this project follows the BeamMP website’s standard license. If clarifications are needed, open an issue and we will update this section.
+21
View File
@@ -0,0 +1,21 @@
{
"$schema": "https://shadcn-vue.com/schema.json",
"style": "new-york",
"typescript": false,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/style.css",
"baseColor": "gray",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"composables": "@/composables"
},
"registries": {}
}
+74
View File
@@ -0,0 +1,74 @@
import pluginVue from 'eslint-plugin-vue'
import js from '@eslint/js'
import prettier from 'eslint-plugin-prettier'
import configPrettier from 'eslint-config-prettier'
export default [
// Ignore patterns (replaces .eslintignore)
{
ignores: ['node_modules', 'dist', '*.log', '.DS_Store'],
},
// Base JavaScript config
js.configs.recommended,
// Vue 3 recommended config
...pluginVue.configs['flat/recommended'],
// Global configuration
{
plugins: {
prettier,
},
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
// Browser globals
window: 'readonly',
document: 'readonly',
navigator: 'readonly',
console: 'readonly',
localStorage: 'readonly',
fetch: 'readonly',
alert: 'readonly',
prompt: 'readonly',
getComputedStyle: 'readonly',
// Node globals
process: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
module: 'readonly',
require: 'readonly',
},
},
rules: {
// Prettier integration
...configPrettier.rules,
'prettier/prettier': 'error',
// Vue-specific rules
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'warn',
'vue/require-default-prop': 'off',
'vue/require-prop-types': 'warn',
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'always',
component: 'always',
},
},
],
// General JavaScript rules
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'prefer-const': 'error',
'no-var': 'error',
},
},
]
-3
View File
@@ -1,3 +0,0 @@
INSTANCES=3
DEBUG=false
PORT=3000
-7
View File
@@ -1,7 +0,0 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
-13
View File
@@ -1,13 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BeamMP</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
-5395
View File
File diff suppressed because it is too large. Load diff
-30
View File
@@ -1,30 +0,0 @@
{
"name": "beammp-website-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@headlessui/vue": "^1.7.16",
"@heroicons/vue": "^2.0.18",
"@statnett/vue-plotly": "^0.3.2",
"axios": "^1.6.2",
"plotly.js": "^2.27.1",
"plotly.js-dist": "^2.27.1",
"plotly.js-dist-min": "^2.27.1",
"uuid": "^9.0.1",
"vue": "^3.3.8",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.0",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"tailwindcss": "^3.3.6",
"vite": "^5.0.0"
}
}
-6
View File
@@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-10
View File
@@ -1,10 +0,0 @@
<script setup>
import Navbar from '@/components/NavBar.vue'
import Footer from '@/components/Footer.vue'
</script>
<template>
<Navbar />
<router-view />
<Footer />
</template>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

-121
View File
@@ -1,121 +0,0 @@
<template>
<div class="bg-gray-800 text-gray-400">
<div class="px-4 pt-16 mx-auto md:max-w-full lg:max-w-screen-xl md:px-24 lg:px-8">
<div class="grid gap-16 row-gap-10 mb-8 lg:grid-cols-6">
<div class="md:max-w-md lg:col-span-2">
<a href="/" aria-label="Go home" title="Company" class="inline-flex items-center">
<img class="h-8 w-auto" src="../assets/beammp-logo.png" alt="BeamMP Logo" />
<span class="ml-4 text-xl font-bold tracking-wide text-gray-200 uppercase">BeamMP</span>
</a>
<div class="mt-4 lg:max-w-sm">
<p class="text-sm text-gray-300">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.
</p>
<p class="mt-4 text-sm text-gray-300">
Eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
</div>
</div>
<div class="grid grid-cols-2 gap-5 row-gap-8 lg:col-span-4 md:grid-cols-4">
<div>
<p class="font-semibold tracking-wide text-gray-200">Sites</p>
<ul class="mt-2 space-y-2">
<li>
<a href="https://patreon.com/beammp" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Patreon</a>
</li>
<li>
<a href="https://forum.beammp.com/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Forum</a>
</li>
<li>
<a href="https://keymaster.beammp.com/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Keymaster</a>
</li>
<li>
<a href="https://docs.beammp.com/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Docs</a>
</li>
<li>
<a href="https://store.beammp.com/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Store</a>
</li>
</ul>
</div>
<div>
<p class="font-semibold tracking-wide text-gray-200">GitHub</p>
<ul class="mt-2 space-y-2">
<li>
<a href="https://github.com/BeamMP/BeamMP" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Mod</a>
</li>
<li>
<a href="https://github.com/BeamMP/BeamMP-Launcher" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Launcher</a>
</li>
<li>
<a href="https://github.com/BeamMP/BeamMP-Server" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Server</a>
</li>
</ul>
</div>
<div>
<p class="font-semibold tracking-wide text-gray-200">?</p>
<ul class="mt-2 space-y-2">
<li>
<a href="/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">?</a>
</li>
<li>
<a href="/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">?</a>
</li>
<li>
<a href="/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">?</a>
</li>
<li>
<a href="/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">?</a>
</li>
<li>
<a href="/" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">?</a>
</li>
</ul>
</div>
<div>
<p class="font-semibold tracking-wide text-gray-200">Documents</p>
<ul class="mt-2 space-y-2">
<li>
<a href="/rules" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Rules</a>
</li>
<li>
<a href="/privacy" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Privacy policy</a>
</li>
<li>
<a href="/terms" class="text-gray-300 transition-colors duration-300 hover:text-deep-purple-accent-400">Terms</a>
</li>
</ul>
</div>
</div>
</div>
<div class="flex flex-col justify-between pt-5 pb-10 border-t sm:flex-row">
<p class="text-sm text-gray-300">
© Copyright 2024 BeamMP. All rights reserved.
</p>
<div class="flex items-center mt-4 space-x-4 sm:mt-0">
<a href="/" class="text-gray-400 transition-colors duration-300 hover:text-deep-purple-accent-400">
<svg viewBox="0 0 24 24" fill="currentColor" class="h-5">
<path
d="M24 4.6c-0.9 0.4-1.8 0.7-2.8 0.8c1-0.6 1.8-1.6 2.2-2.7c-1 0.6-2 1-3.1 1.2c-0.9-1-2.2-1.6-3.6-1.6 c-2.7 0-4.9 2.2-4.9 4.9c0 0.4 0 0.8 0.1 1.1C7.7 8.1 4.1 6.1 1.7 3.1C1.2 3.9 1 4.7 1 5.6c0 1.7 0.9 3.2 2.2 4.1 C2.4 9.7 1.6 9.5 1 9.1c0 0 0 0 0 0.1c0 2.4 1.7 4.4 3.9 4.8c-0.4 0.1-0.8 0.2-1.3 0.2c-0.3 0-0.6 0-0.9-0.1c0.6 2 2.4 3.4 4.6 3.4 c-1.7 1.3-3.8 2.1-6.1 2.1c-0.4 0-0.8 0-1.2-0.1c2.2 1.4 4.8 2.2 7.5 2.2c9.1 0 14-7.5 14-14c0-0.2 0-0.4 0-0.6 C22.5 6.4 23.3 5.5 24 4.6z"
></path>
</svg>
</a>
<a href="/" class="text-gray-400 transition-colors duration-300 hover:text-deep-purple-accent-400">
<svg viewBox="0 0 30 30" fill="currentColor" class="h-6">
<circle cx="15" cy="15" r="4"></circle>
<path
d="M19.999 3h-10C6.14 3 3 6.141 3 10.001v10C3 23.86 6.141 27 10.001 27h10C23.86 27 27 23.859 27 19.999v-10 C27 6.14 23.859 3 19.999 3z M15 21c-3.309 0-6-2.691-6-6s2.691-6 6-6s6 2.691 6 6S18.309 21 15 21z M22 9c-0.552 0-1-0.448-1-1 c0-0.552 0.448-1 1-1s1 0.448 1 1C23 8.552 22.552 9 22 9z"
></path>
</svg>
</a>
<a href="/" class="text-gray-400 transition-colors duration-300 hover:text-deep-purple-accent-400">
<svg viewBox="0 0 24 24" fill="currentColor" class="h-5">
<path
d="M22 0H2C0.895 0 0 0.895 0 2v20c0 1.105 0.895 2 2 2h11v-9h-3v-4h3V8.413c0-3.1 1.893-4.788 4.659-4.788 c1.325 0 2.463 0.099 2.795 0.143v3.24l-1.918 0.001c-1.504 0-1.795 0.715-1.795 1.763V11h4.44l-1 4h-3.44v9H22c1.105 0 2-0.895 2-2 V2C24 0.895 23.105 0 22 0z"
></path>
</svg>
</a>
</div>
</div>
</div>
</div>
</template>
-152
View File
@@ -1,152 +0,0 @@
<template>
<Disclosure as="nav" class="navbar-bg sticky top-0 z-40" v-slot="{ open }">
<div class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
<div class="relative flex h-16 items-center justify-between">
<div class="absolute inset-y-0 left-0 flex items-center sm:hidden">
<!-- Mobile menu button-->
<DisclosureButton
class="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
<span class="absolute -inset-0.5" />
<span class="sr-only">Open main menu</span>
<Bars3Icon v-if="!open" class="block h-6 w-6" aria-hidden="true" />
<XMarkIcon v-else class="block h-6 w-6" aria-hidden="true" />
</DisclosureButton>
</div>
<div class="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
<div class="flex flex-shrink-0 items-center">
<a href="/"><img class="h-8 w-auto" src="../assets/beammp-logo.png" alt="BeamMP Logo" /></a>
</div>
<div class="hidden sm:ml-6 sm:block">
<div class="flex space-x-4">
<a v-for="item in navigation" :key="item.name" :href="item.href"
:class="[item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white', 'rounded-md px-3 py-2 text-sm font-medium']"
:aria-current="item.current ? 'page' : undefined">{{ item.name }}</a>
</div>
</div>
</div>
<div class="flex items-center">
<div class="flex-shrink-0">
<button type="button" class="relative inline-flex items-center gap-x-1.5 rounded-md bg-orange px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<!--<PlusIcon class="-ml-0.5 h-5 w-5" aria-hidden="true" />-->
Patreon
</button>
</div>
</div>
<!-- Mode Switcher Dropdown -->
<!--<div class="flex items-center border-l border-slate-200 ml-6 pl-6 dark:border-slate-800">
<label class="sr-only" id="headlessui-listbox-label-:Rpkcr6:" data-headlessui-state="">Theme</label>
<button type="button" id="headlessui-listbox-button-:R19kcr6:" aria-haspopup="true" aria-expanded="false" data-headlessui-state="" aria-labelledby="headlessui-listbox-label-:Rpkcr6: headlessui-listbox-button-:R19kcr6:" class="">
<span class="dark:hidden">
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6">
<path d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" class="stroke-slate-400 dark:stroke-slate-500"></path>
<path
d="M12 4v1M17.66 6.344l-.828.828M20.005 12.004h-1M17.66 17.664l-.828-.828M12 20.01V19M6.34 17.664l.835-.836M3.995 12.004h1.01M6 6l.835.836"
class="stroke-slate-400 dark:stroke-slate-500"></path>
</svg>
</span>
<span class="hidden dark:inline">
<svg viewBox="0 0 24 24" fill="none" class="w-6 h-6">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M17.715 15.15A6.5 6.5 0 0 1 9 6.035C6.106 6.922 4 9.645 4 12.867c0 3.94 3.153 7.136 7.042 7.136 3.101 0 5.734-2.032 6.673-4.853Z"
class="fill-transparent"></path>
<path
d="m17.715 15.15.95.316a1 1 0 0 0-1.445-1.185l.495.869ZM9 6.035l.846.534a1 1 0 0 0-1.14-1.49L9 6.035Zm8.221 8.246a5.47 5.47 0 0 1-2.72.718v2a7.47 7.47 0 0 0 3.71-.98l-.99-1.738Zm-2.72.718A5.5 5.5 0 0 1 9 9.5H7a7.5 7.5 0 0 0 7.5 7.5v-2ZM9 9.5c0-1.079.31-2.082.845-2.93L8.153 5.5A7.47 7.47 0 0 0 7 9.5h2Zm-4 3.368C5 10.089 6.815 7.75 9.292 6.99L8.706 5.08C5.397 6.094 3 9.201 3 12.867h2Zm6.042 6.136C7.718 19.003 5 16.268 5 12.867H3c0 4.48 3.588 8.136 8.042 8.136v-2Zm5.725-4.17c-.81 2.433-3.074 4.17-5.725 4.17v2c3.552 0 6.553-2.327 7.622-5.537l-1.897-.632Z"
class="fill-slate-400 dark:fill-slate-500"></path>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M17 3a1 1 0 0 1 1 1 2 2 0 0 0 2 2 1 1 0 1 1 0 2 2 2 0 0 0-2 2 1 1 0 1 1-2 0 2 2 0 0 0-2-2 1 1 0 1 1 0-2 2 2 0 0 0 2-2 1 1 0 0 1 1-1Z"
class="fill-slate-400 dark:fill-slate-500"></path>
</svg>
</span>
</button>
</div>-->
<!--<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
<button type="button" class="relative rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
<span class="absolute -inset-1.5" />
<span class="sr-only">View notifications</span>
<BellIcon class="h-6 w-6" aria-hidden="true" />
</button>-->
<!-- Profile dropdown - From the Forum Accounts System -->
<!--<Menu as="div" class="relative ml-3">
<div>
<MenuButton class="relative flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
<span class="absolute -inset-1.5" />
<span class="sr-only">Open user menu</span>
<img class="h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="" />
</MenuButton>
</div>
<transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
<MenuItems class="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<MenuItem v-slot="{ active }">
<a href="#" :class="[active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700']">Your Profile</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a href="#" :class="[active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700']">Settings</a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a href="#" :class="[active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700']">Sign out</a>
</MenuItem>
</MenuItems>
</transition>
</Menu>-->
<!--</div>-->
</div>
</div>
<DisclosurePanel class="sm:hidden">
<div class="space-y-1 px-2 pb-3 pt-2">
<DisclosureButton v-for="item in navigation" :key="item.name" as="a" :href="item.href"
:class="[item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white', 'block rounded-md px-3 py-2 text-base font-medium']"
:aria-current="item.current ? 'page' : undefined">{{ item.name }}</DisclosureButton>
</div>
</DisclosurePanel>
</Disclosure>
</template>
<style scoped>
.navbar-bg {
background: #00000060;
}
.bg-orange {
background: var('beammp-orange');
}
</style>
<script>
export default {
methods: {
//setTheme(theme) {
// if (theme === 'light') {
// document.documentElement.classList.remove('dark');
// } else if (theme === 'dark') {
// document.documentElement.classList.add('dark');
// } else if (theme === 'system') {
// document.documentElement.classList.remove('dark');
// }
//},
},
};
</script>
<script setup>
import { Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
import { Bars3Icon, BellIcon, XMarkIcon } from '@heroicons/vue/24/outline'
const navigation = [
{ name: 'Forum', href: 'https://forum.beammp.com/', current: false },
{ name: 'Docs', href: 'https://docs.beammp.com/', current: false },
{ name: 'Stats', href: '/stats', current: false },
{ name: 'Servers', href: '/servers', current: false },
{ name: 'Hosting', href: '/hosting', current: false },
{ name: 'Events', href: 'https://forum.beammp.com/c/important/events/25', current: false },
{ name: 'Store', href: 'https://store.beammp.com/', current: false },
{ name: 'GitHub', href: 'https://github.com/BeamMP', current: false },
{ name: 'Patreon', href: 'https://patreon.com/BeamMP', current: false },
]
var isOpen = false
</script>
@@ -1,14 +0,0 @@
<template>
<div class="bg-white py-24 sm:py-32">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<h2 class="text-center text-lg font-semibold leading-8 text-gray-900">Used by some of the largest and most innovative BeamNG communities</h2>
<div class="mx-auto mt-10 grid max-w-lg grid-cols-4 items-center gap-x-8 gap-y-10 sm:max-w-xl sm:grid-cols-6 sm:gap-x-10 lg:mx-0 lg:max-w-none lg:grid-cols-5">
<a href="https://discord.gg/carp"><img class="col-span-2 max-h-10 w-full object-contain lg:col-span-1" src="@/assets/communities/carp-logo.png" alt="CaRP" width="158" height="48" /></a>
<a href="https://discord.2fast.racing/"><img class="col-span-2 max-h-12 w-full object-contain lg:col-span-1" src="@/assets/communities/2fast-logo.png" alt="2FastRacing" width="158" height="48" /></a>
<a href="https://discord.beamcruise.com"><img class="col-span-2 max-h-12 w-full object-contain lg:col-span-1" src="@/assets/communities/beamcruise-logo.png" alt="Beam\\Cruise" width="158" height="48" /></a>
<a href="https://discord.gg/b9G3fXKqpg"><img class="col-span-2 max-h-12 w-full object-contain lg:col-span-1" src="@/assets/communities/nuclear-logo.png" alt="CnR" width="158" height="48" /></a>
<img class="col-span-2 col-start-2 max-h-12 w-full object-contain sm:col-start-auto lg:col-span-1" src="@/assets/beammp-logo.png" alt="Community E" width="158" height="48" />
</div>
</div>
</div>
</template>
-27
View File
@@ -1,27 +0,0 @@
<template>
<div class="bg-white">
<div class="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
<div class="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
<svg viewBox="0 0 1024 1024" class="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0" aria-hidden="true">
<circle cx="512" cy="512" r="512" fill="url(#759c1415-0410-454c-8f7c-9a820de03641)" fill-opacity="0.7" />
<defs>
<radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
<stop stop-color="#7775D6" />
<stop offset="1" stop-color="#E935C1" />
</radialGradient>
</defs>
</svg>
<div class="mx-auto max-w-md text-center lg:mx-0 lg:flex-auto lg:py-32 lg:text-left">
<h2 class="text-3xl font-bold tracking-tight text-white sm:text-4xl">Looking to write your own mods, plugins or resources?</h2>
<p class="mt-6 text-lg leading-8 text-gray-300">Check out our docs to get you started with developing your own mods and resources.</p>
<div class="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
<a href="https://docs.beammp.com" class="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white">Learn more <span aria-hidden="true">→</span></a>
</div>
</div>
<div class="relative mt-16 h-80 lg:mt-8">
<img class="absolute left-0 top-0 w-[57rem] max-w-none rounded-md bg-white/5 ring-1 ring-white/10" src="https://tailwindui.com/img/component-images/dark-project-app-screenshot.png" alt="App screenshot" width="1824" height="1080" />
</div>
</div>
</div>
</div>
</template>
@@ -1,48 +0,0 @@
<template>
<div class="overflow-hidden bg-white py-24 sm:py-32">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<div class="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
<div class="lg:pr-8 lg:pt-4">
<div class="lg:max-w-lg">
<h2 class="text-base font-semibold leading-7 text-indigo-600">Integrated Server list</h2>
<p class="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Choose a server to your liking</p>
<p class="mt-6 text-lg leading-8 text-gray-600">BeamMP has a builtin server list allowing you to select the server that appeals to your liking the most.</p>
<dl class="mt-10 max-w-xl space-y-8 text-base leading-7 text-gray-600 lg:max-w-none">
<div v-for="feature in features" :key="feature.name" class="relative pl-9">
<dt class="inline font-semibold text-gray-900">
<component :is="feature.icon" class="absolute left-1 top-1 h-5 w-5 text-indigo-600" aria-hidden="true" />
{{ feature.name }}
</dt>
{{ ' ' }}
<dd class="inline">{{ feature.description }}</dd>
</div>
</dl>
</div>
</div>
<img src="@/assets/beammp-servers.png" alt="Product screenshot" class="w-[48rem] max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-[57rem] md:-ml-4 lg:-ml-0" width="2432" height="1442" />
</div>
</div>
</div>
</template>
<script setup>
import { CloudArrowUpIcon, LockClosedIcon, ServerIcon } from '@heroicons/vue/20/solid'
const features = [
{
name: 'Custom mods',
description: 'BeamMP includes resource sharing functionality so that you can share your favorite mods with your friends directly from the same server. This applies with each and every server too!',
icon: CloudArrowUpIcon,
},
{
name: 'Public & Private Servers',
description: 'You have full control over your server including if you want it public for others to join or not.',
icon: LockClosedIcon,
},
{
name: 'Self and Paid Hosting',
description: 'You are free to host your own server or check out one of our parters who can have you up and running in minutes.',
icon: ServerIcon,
},
]
</script>
@@ -1,48 +0,0 @@
<template>
<div class="overflow-hidden bg-white py-24 sm:py-32">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<div class="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
<div class="lg:pr-8 lg:pt-4">
<div class="lg:max-w-lg">
<h2 class="text-base font-semibold leading-7 text-indigo-600">Integrated Server list</h2>
<p class="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Choose a server to your liking</p>
<p class="mt-6 text-lg leading-8 text-gray-600">BeamMP has a builtin server list allowing you to select the server that appeals to your liking the most.</p>
<dl class="mt-10 max-w-xl space-y-8 text-base leading-7 text-gray-600 lg:max-w-none">
<div v-for="feature in features" :key="feature.name" class="relative pl-9">
<dt class="inline font-semibold text-gray-900">
<component :is="feature.icon" class="absolute left-1 top-1 h-5 w-5 text-indigo-600" aria-hidden="true" />
{{ feature.name }}
</dt>
{{ ' ' }}
<dd class="inline">{{ feature.description }}</dd>
</div>
</dl>
</div>
</div>
<img src="@/assets/beammp-servers.png" alt="Product screenshot" class="w-[48rem] max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-[57rem] md:-ml-4 lg:-ml-0" width="2432" height="1442" />
</div>
</div>
</div>
</template>
<script setup>
import { CloudArrowUpIcon, LockClosedIcon, ServerIcon } from '@heroicons/vue/20/solid'
const features = [
{
name: 'Custom mods',
description: 'BeamMP includes resource sharing functionality so that you can share your favorite mods with your friends directly from the same server. This applies with each and every server too!',
icon: CloudArrowUpIcon,
},
{
name: 'Public & Private Servers',
description: 'You have full control over your server including if you want it public for others to join or not.',
icon: LockClosedIcon,
},
{
name: 'Self and Paid Hosting',
description: 'You are free to host your own server or check out one of our parters who can have you up and running in minutes.',
icon: ServerIcon,
},
]
</script>
-58
View File
@@ -1,58 +0,0 @@
<template>
<header class="main-content" :style="{ 'background-position': 'center center, center 0px' }">
<div class="introduction" style="margin-top: 0px;">
<div class="container mx-auto">
<div class="flex items-center justify-center">
<div class="lg:w-8/12 md:w-8/12 sm:w-8/12 xs:w-full">
<p class="lead">
<b>BeamMP</b> Bringing Multiplayer to BeamNG.drive!<br>
With a smooth and enjoyable experience.
</p>
</div>
<div id="button" class="lg:w-4/12 md:w-4/12 sm:w-4/12 xs:w-full hidden-xs buttons-wrapper">
<div class="buttons mt-3">
<button @click="downloadInstaller" class="download-client js-show-story" href="beamMP.zip" download="">
<img class="os-icon" src="https://raw.githubusercontent.com/devicons/devicon/master/icons/windows8/windows8-original.svg" alt="windows-logo">
<span class="text">Download Client</span>
<span class="description"> BeamMP_Installer.zip</span>
</button>
</div>
<div class="buttons mt-3">
<form action="https://github.com/BeamMP/BeamMP-Server/releases/latest/download/BeamMP-Server.exe">
<button class="download-client js-show-story" style="background: radial-gradient(circle,rgb(255 179 38 / 80%),rgb(255 176 0 / 65%)) center/100%;">
<img class="os-icon" src="https://raw.githubusercontent.com/devicons/devicon/master/icons/windows8/windows8-original.svg" alt="windows-logo">
<span class="text">Download Server</span>
<span class="description"> BeamMP-Server.exe</span>
</button>
</form>
</div>
<div class="buttons mt-3">
<form action="https://github.com/BeamMP/BeamMP-Server/releases/latest">
<button class="download-client js-show-story" style="background: radial-gradient(circle,rgb(255 179 38 / 80%),rgb(255 176 0 / 65%)) center/100%;">
<img class="os-icon" src="https://raw.githubusercontent.com/devicons/devicon/master/icons/linux/linux-plain.svg" alt="linux-logo">
<span class="text">Download Server</span>
<span class="description">Linux builds</span>
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</header>
</template>
<script>
export default {
methods: {
downloadInstaller() {
// Implement your download logic here
// You can use the window.location.href or any other method
}
}
}
</script>
<style scoped>
/* Add your Tailwind CSS styles here */
</style>
-16
View File
@@ -1,16 +0,0 @@
<template>
<div class="bg-white py-24 sm:py-32">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<h2 class="text-center text-lg font-semibold leading-8 text-gray-900">Proudly partnered with trusted hosting companies</h2>
<div v-for="partner in partners" :key="partner.id" class="mx-auto mt-10 grid max-w-lg grid-cols-4 items-center gap-x-8 gap-y-10 sm:max-w-xl sm:grid-cols-6 sm:gap-x-10 lg:mx-0 lg:max-w-none lg:grid-cols-5">
<a :href="partner.link"><img class="col-span-2 max-h-12 w-full object-contain lg:col-span-1" :src="partner.logo" :alt="partner.alt" width="158" height="48" /></a>
</div>
</div>
</div>
</template>
<script setup>
const partners = [
{ id: 1, logo: 'src/assets/partners/horizon_hosting-logo.png', alt: 'Horizon Hosting', link: 'https://billing.horizonnetworks.uk/store/beammp-server-hosting' },
]
</script>
-21
View File
@@ -1,21 +0,0 @@
<template>
<div class="bg-white dark:bg-slate-800 py-24 sm:py-32">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<dl class="grid grid-cols-1 gap-x-8 gap-y-16 text-center lg:grid-cols-4">
<div v-for="stat in stats" :key="stat.id" class="mx-auto flex max-w-xs flex-col gap-y-4">
<a :href="stat.link"><dt class="text-base leading-7 text-gray-600 dark:text-white">{{ stat.name }}</dt></a>
<dd class="order-first text-3xl font-semibold tracking-tight text-gray-900 sm:text-5xl dark:text-slate-400">{{ stat.value }}</dd>
</div>
</dl>
</div>
</div>
</template>
<script setup>
const stats = [
{ id: 1, name: 'Players Online', value: '1500', link: '/stats' },
{ id: 2, name: 'Public Servers', value: '1200', link: '/stats' },
{ id: 3, name: 'Users', value: '+760,000', link: 'https://forum.beammp.com' },
{ id: 4, name: 'Discord Members', value: '+190,000', link: 'https://discord.com/servers/beammp-601558901657305098' },
]
</script>
@@ -1,169 +0,0 @@
<template>
<div class="expanded-row-details">
<h1 style="padding-left:10px;display:flex;">
<template v-if="rowData.raw.official">
<img src="/src/assets/beammp-logo.png" alt="" style="height: 23px; padding-right: 10px;"> [Official Server]
</template>
<template v-else>
<img src="/src/assets/beammp-logo.png" alt="" style="height: 23px; padding-right: 10px;">
</template>
<span v-for="(value, name) in rowData.name" :style="value.f">{{ value.s }}</span>
</h1>
<div class="columns-2">
<div>
<h2 class="text-xl">Information:</h2>
<hr/>
<table class="description-table">
<tr>
<td>Owner:</td>
<td>{{rowData.raw.owner|| ""}}</td>
</tr>
<tr>
<td>Map:</td>
<td>{{rowData.map || ""}}</td>
</tr>
</table>
</div>
<div>
<div>
<h2 class="text-xl">Description:</h2>
<hr/>
<p><span v-for="(value, name) in formatDescriptionName(rowData.raw.sdesc)" :style="value.f">{{ value.s }}</span></p>
</div>
<div>
<h2 class="text-xl">Mods ({{modCount(rowData.raw.modlist|| "")}}):</h2>
<hr/>
<p>{{modList(rowData.raw.modlist|| "")}} ({{formatBytes(rowData.raw.modstotalsize) || "0B"}})</p>
</div>
</div>
</div>
<div class="row">
<h1 class="text-xl">Players ({{rowData.players|| "0"}}):</h1>
<hr/>
<p>{{listPlayers(rowData.raw.playerslist|| "")}}</p>
</div>
</div>
</template>
<script>
var descStyleMap = {
'^0': 'color:#000000',
'^1': 'color:#0000AA',
'^2': 'color:#00AA00',
'^3': 'color:#00AAAA',
'^4': 'color:#AA0000',
'^5': 'color:#AA00AA',
'^6': 'color:#FFAA00',
'^7': 'color:#AAAAAA',
'^8': 'color:#555555',
'^9': 'color:#5555FF',
'^a': 'color:#55FF55',
'^b': 'color:#55FFFF',
'^c': 'color:#FF5555',
'^d': 'color:#FF55FF',
'^e': 'color:#FFFF55',
'^f': 'color:#FFFFFF',
'^l': 'font-weight:bold',
'^m': 'text-decoration:line-through',
'^n': 'text-decoration:underline',
'^o': 'font-style:italic',
};
export default {
props: {
rowData: {
type: Object,
required: true,
},
},
methods: {
modCount(s) {
if(s.length==0) return 0;
return s.split(";").length-1;
},
modList(s) {
var modarray = s.split(';');
//console.log(modarray);
s = "";
for (var i=0; i<modarray.length-1; i++){
var modName = modarray[i].split('/').pop();
modName = modName.replace(".zip","");
s += modName;
//if (i<modarray.length-2)
s += ", ";
}
//console.log(s);
s = s.substring(0, s.length -2);
return s
},
formatBytes(bytes = 0, decimals = 2) {
if (bytes == 0 || bytes == undefined) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
},
listPlayers(s) {
if (s != undefined || s != "") {
var re = new RegExp(";", 'g');
s = s.replace(re, ', ');
s = s.substring(0, s.length -2);
return s
} else {
return "No players..."
}
},
applyCode(string, codes) {
var cssText = ''
string = string.replace(/\x00*/g, '');
for (var i = 0, len = codes.length; i < len; i++) {
cssText += styleMap[codes[i]] + ';';
}
return {s: string, f:cssText};
},
formatDescriptionName(string) {
var codes = string.match(/\^.{1}/g) || [],
indexes = [],
apply = [],
tmpStr,
name = [],
i,
len;
for (i = 0, len = codes.length; i < len; i++) {
indexes.push(string.indexOf(codes[i]));
string = string.replace(codes[i], '\x00\x00');
}
if (indexes[0] !== 0) {
name.push(this.applyCode(string.substring(0, indexes[0]), []))
}
for (i = 0; i < len; i++) {
var indexDelta = indexes[i + 1] - indexes[i];
if (indexDelta === 2) {
while (indexDelta === 2) {
apply.push(codes[i]);
i++;
indexDelta = indexes[i + 1] - indexes[i];
}
apply.push(codes[i]);
} else {
apply.push(codes[i]);
}
if (apply.lastIndexOf('^r') > -1) {
apply = apply.slice(apply.lastIndexOf('^r') + 1);
}
tmpStr = string.substring(indexes[i], indexes[i + 1]);
name.push(this.applyCode(tmpStr, apply))
}
return name
}
}
};
</script>
<style scoped>/* Add styles for the expanded row details */
.expanded-row-details {
padding: 10px;
background-color: #f5f5f5;
}</style>
-84
View File
@@ -1,84 +0,0 @@
<template>
<div class="table-container">
<table class="min-w-full divide-y divide-gray-400">
<thead>
<tr>
<th v-for="column in columns" :key="column.key" class="px-6 py-3 bg-gray-200 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
{{ column.label }}
</th>
</tr>
</thead>
<tbody>
<template v-for="item in data" :key="item.id">
<tr @click="selectRow(item.id)" class="servers-table-row">
<td v-for="column in columns" :key="column.key" class="px-6 py-1 whitespace-no-wrap text-sm leading-5 text-gray-600" :style="item.style" >
<template v-if="column.key == 'location'">
<span style="display:flex;width: 125px;">
<img :src="`/src/assets/flags/${item.cc}.png`" alt="" style="padding-right: 10px;">
<span style="position: absolute;left: 105px;">{{ item[column.key] }}</span>
</span>
</template>
<template v-else-if="column.key == 'name'">
<span v-for="(value, name) in item[column.key]" :style="value.f">{{ value.s }}</span>
</template>
<template v-else>
{{ item[column.key] }}
</template>
</td>
</tr>
<tr v-if="selectedRow == item.id">
<td :colspan="columns.length">
<ExpandedRowDetails :rowData="getExpandedRowData(item)" />
</td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
<script>
import ExpandedRowDetails from "@/components/servers/ExpandedRowDetails.vue";
export default {
components: {
ExpandedRowDetails,
},
props: {
columns: {
type: Array,
required: true,
},
data: {
type: Array,
required: true,
},
},
data() {
return {
selectedRow: null,
};
},
methods: {
selectRow(id) {
if (this.selectedRow === id) {
this.selectedRow = null;
} else {
this.selectedRow = id;
}
},
getExpandedRowData(item) {
return item || {}
},
},
};
</script>
<style scoped>
.table-container {
overflow-x: auto;
}
.servers-table-row:hover {
background-color: rgba(0, 0, 0, 0.25);
}
</style>
-82
View File
@@ -1,82 +0,0 @@
<!-- https://github.com/VanOord/vue3-plotly/pull/10/files -->
<template>
<div :id="plotlyId"></div>
</template>
<script>
let Plotly;
import events from "./events.js";
import { v4 as uuidv4 } from 'uuid';
let timeOutFunctionId;
export default {
name: 'VuePlotly',
data() {
return {
plotlyId: `plotly-${uuidv4()}`,
};
},
props: {
'data' : {
type : Array,
required:false,
},
'layout': {
type : Object,
required:false,
},
'config':{
type : Object,
required:false,
},
'bundle':{
type : String,
default : "full",
required:false
}
},
watch: {
data() { this.setGraph(); },
layout() { this.setGraph(); },
config() { this.setGraph(); },
},
async mounted() {
switch(this.bundle){
//case "basic" : Plotly = await import("plotly.js-basic-dist-min"); break;
//case "cartesian" : Plotly = await import("plotly.js-cartesian-dist-min"); break;
//case "geo" : Plotly = await import("plotly.js-geo-dist-min"); break;
//case "gl3d" : Plotly = await import("plotly.js-gl3d-dist-min"); break;
//case "gl2d" : Plotly = await import("plotly.js-gl2d-dist-min"); break;
//case "mapbox" : Plotly = await import("plotly.js-mapbox-dist-min"); break;
//case "finance" : Plotly = await import("plotly.js-finance-dist-min"); break;
//case "strict" : Plotly = await import("plotly.js-strict-dist-min"); break;
default : Plotly = await import("plotly.js-dist");
}
this.setGraph();
events.forEach(evt => {
this.$el.on(evt.completeName, evt.handler(this));
});
this.resizeObserver = new ResizeObserver(() => {
clearTimeout(timeOutFunctionId); // debounce the reset
timeOutFunctionId = setTimeout(this.setGraph, 100);
});
this.resizeObserver.observe(document.getElementById(this.plotlyId));
},
beforeUnmount() {
events.forEach(event => this.$el.removeAllListeners(event.completeName));
this.resizeObserver.disconnect();
},
methods: {
setGraph() {
Plotly.newPlot(this.plotlyId, this.data, this.layout, this.config);
},
},
};
</script>
-40
View File
@@ -1,40 +0,0 @@
const eventsName = [
"AfterExport",
"AfterPlot",
"Animated",
"AnimatingFrame",
"AnimationInterrupted",
"AutoSize",
"BeforeExport",
"ButtonClicked",
"Click",
"ClickAnnotation",
"Deselect",
"DoubleClick",
"Framework",
"Hover",
"LegendClick",
"LegendDoubleClick",
"Relayout",
"Restyle",
"Redraw",
"Selected",
"Selecting",
"SliderChange",
"SliderEnd",
"SliderStart",
"Transitioning",
"TransitionInterrupted",
"Unhover"
];
const events = eventsName
.map(evt => evt.toLocaleLowerCase())
.map(eventName => ({
completeName: "plotly_" + eventName,
handler: context => (...args) => {
context.$emit.apply(context, [eventName, ...args]);
}
}));
export default events;
-6
View File
@@ -1,6 +0,0 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
-36
View File
@@ -1,36 +0,0 @@
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home,
},
{
path: '/stats',
component: () => import('@/views/Stats.vue'),
},
{
path: '/servers',
component: () => import('@/views/Servers.vue'),
},
{
path: '/hosting',
component: () => import('@/views/Hosting.vue'),
},
{
path: '/rules',
component: () => import('@/views/Rules.vue'),
},
{
path: '/privacy',
component: () => import('@/views/Privacy.vue'),
},
{
path: '/terms',
component: () => import('@/views/Terms.vue'),
},
],
})
-118
View File
@@ -1,118 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.main-content {
display: flex;
position: relative;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
width: 100%;
height: calc(100vh - 80px);
overflow: hidden;
background: linear-gradient(-45deg, rgba(22, 25, 35, 0.35) 0%, rgba(22, 25, 35, 0.95) 100%) center center/100%, url(./assets/beamng-mp-landing.png) center top/cover;
color: #fefee1;
}
.main-content .introduction {
width: 100%;
position: absolute;
transition: transform .2s ease;
transform: translateX(0);
}
.main-content .lead {
font-size: 30px;
font-weight: 300;
font-family: verdana;
}
.middle-xs {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.center-xs {
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
text-align: center;
}
.main-content .buttons-wrapper {
display: flex;
flex-direction: column;
align-items: flex-end;
align-content: flex-end;
}
.main-content .buttons-wrapper .buttons .download-client {
display: block;
position: relative;
padding: 15px 25px 15px 25px;
cursor: pointer;
color: #fefee1;
border: none;
text-shadow: 0 0 1px rgba(22, 25, 35, 0.5);
background: radial-gradient(circle, rgba(150, 204, 0, 0.8), rgba(150, 204, 0, 0.65)) center/100%;
transition: box-shadow .2s ease;
font-size: 27px;
font-weight: 300;
line-height: 1;
border-radius: 3px;
text-decoration: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
min-width: 297px;
padding-left: 40px;
}
.description {
display: block;
font-size: 12px;
font-weight: 200;
opacity: .9;
}
div.buttons {
min-width: 297px;
}
div.buttons.mt-3 {
min-width: 297px;
}
img.os-icon {
width: 32px !important;
height: 32px !important;
position: absolute;
top: 18px;
left: 15px;
}
@media screen and (max-width: 600px) {
#button {
display: none;
}
}
@media screen and (max-width: 767px) {
.text {
display: none;
}
.logo-link {
display: flex;
height: 100%;
align-items: center;
align-content: center;
}
.logo-text {
margin: 0 auto;
}
}
-19
View File
@@ -1,19 +0,0 @@
<script setup>
import Hero from '@/components/home/Hero.vue'
import Stats from '@/components/home/Stats.vue'
import Communities from '@/components/home/Communities.vue'
import Partners from '@/components/home/Partners.vue'
import Featured2 from '@/components/home/Featured2.vue'
import Docs from '@/components/home/Docs.vue'
</script>
<template>
<Hero />
<Stats />
<Communities />
<Featured2 />
<Partners />
<!-- Coders Portion -->
<Docs />
</template>
-3
View File
@@ -1,3 +0,0 @@
<template>
<h1>BeamMP Privacy Policy</h1>
</template>
-3
View File
@@ -1,3 +0,0 @@
<template>
<h1>BeamMP Privacy Policy</h1>
</template>
-3
View File
@@ -1,3 +0,0 @@
<template>
<h1>BeamMP Rules</h1>
</template>
-440
View File
@@ -1,440 +0,0 @@
<script setup>
import Table from '@/components/servers/Table.vue'
</script>
<template>
<div id="app" class="p-8">
<Table :columns="columns" :data="tableData" />
</div>
</template>
<script>
import axios from 'axios'
var styleMap = {
'^0': 'color:#000000',
'^1': 'color:#0000AA',
'^2': 'color:#00AA00',
'^3': 'color:#00AAAA',
'^4': 'color:#AA0000',
'^5': 'color:#AA00AA',
'^6': 'color:#FFAA00',
'^7': 'color:#AAAAAA',
'^8': 'color:#555555',
'^9': 'color:#5555FF',
'^a': 'color:#55FF55',
'^b': 'color:#55FFFF',
'^c': 'color:#FF5555',
'^d': 'color:#FF55FF',
'^e': 'color:#FFFF55',
'^f': 'color:#FFFFFF',
'^l': 'font-weight:bold',
'^m': 'text-decoration:line-through',
'^n': 'text-decoration:underline',
'^o': 'font-style:italic',
};
const isoCountries = {
'AF': 'Afghanistan',
'AX': 'Aland Islands',
'AL': 'Albania',
'DZ': 'Algeria',
'AS': 'American Samoa',
'AD': 'Andorra',
'AO': 'Angola',
'AI': 'Anguilla',
'AQ': 'Antarctica',
'AG': 'Antigua And Barbuda',
'AR': 'Argentina',
'AM': 'Armenia',
'AW': 'Aruba',
'AU': 'Australia',
'AT': 'Austria',
'AZ': 'Azerbaijan',
'BS': 'Bahamas',
'BH': 'Bahrain',
'BD': 'Bangladesh',
'BB': 'Barbados',
'BY': 'Belarus',
'BE': 'Belgium',
'BZ': 'Belize',
'BJ': 'Benin',
'BM': 'Bermuda',
'BT': 'Bhutan',
'BO': 'Bolivia',
'BA': 'Bosnia And Herzegovina',
'BW': 'Botswana',
'BV': 'Bouvet Island',
'BR': 'Brazil',
'IO': 'British Indian Ocean Territory',
'BN': 'Brunei Darussalam',
'BG': 'Bulgaria',
'BF': 'Burkina Faso',
'BI': 'Burundi',
'KH': 'Cambodia',
'CM': 'Cameroon',
'CA': 'Canada',
'CV': 'Cape Verde',
'KY': 'Cayman Islands',
'CF': 'Central African Republic',
'TD': 'Chad',
'CL': 'Chile',
'CN': 'China',
'CX': 'Christmas Island',
'CC': 'Cocos (Keeling) Islands',
'CO': 'Colombia',
'KM': 'Comoros',
'CG': 'Congo',
'CD': 'Congo, Democratic Republic',
'CK': 'Cook Islands',
'CR': 'Costa Rica',
'CI': 'Cote D\'Ivoire',
'HR': 'Croatia',
'CU': 'Cuba',
'CY': 'Cyprus',
'CZ': 'Czech Republic',
'DK': 'Denmark',
'DJ': 'Djibouti',
'DM': 'Dominica',
'DO': 'Dominican Republic',
'EC': 'Ecuador',
'EG': 'Egypt',
'SV': 'El Salvador',
'GQ': 'Equatorial Guinea',
'ER': 'Eritrea',
'EE': 'Estonia',
'ET': 'Ethiopia',
'FK': 'Falkland Islands (Malvinas)',
'FO': 'Faroe Islands',
'FJ': 'Fiji',
'FI': 'Finland',
'FR': 'France',
'GF': 'French Guiana',
'PF': 'French Polynesia',
'TF': 'French Southern Territories',
'GA': 'Gabon',
'GM': 'Gambia',
'GE': 'Georgia',
'DE': 'Germany',
'GH': 'Ghana',
'GI': 'Gibraltar',
'GR': 'Greece',
'GL': 'Greenland',
'GD': 'Grenada',
'GP': 'Guadeloupe',
'GU': 'Guam',
'GT': 'Guatemala',
'GG': 'Guernsey',
'GN': 'Guinea',
'GW': 'Guinea-Bissau',
'GY': 'Guyana',
'HT': 'Haiti',
'HM': 'Heard Island & Mcdonald Islands',
'VA': 'Holy See (Vatican City State)',
'HN': 'Honduras',
'HK': 'Hong Kong',
'HU': 'Hungary',
'IS': 'Iceland',
'IN': 'India',
'ID': 'Indonesia',
'IR': 'Iran, Islamic Republic Of',
'IQ': 'Iraq',
'IE': 'Ireland',
'IM': 'Isle Of Man',
'IL': 'Israel',
'IT': 'Italy',
'JM': 'Jamaica',
'JP': 'Japan',
'JE': 'Jersey',
'JO': 'Jordan',
'KZ': 'Kazakhstan',
'KE': 'Kenya',
'KI': 'Kiribati',
'KR': 'Korea',
'KW': 'Kuwait',
'KG': 'Kyrgyzstan',
'LA': 'Lao People\'s Democratic Republic',
'LV': 'Latvia',
'LB': 'Lebanon',
'LS': 'Lesotho',
'LR': 'Liberia',
'LY': 'Libyan Arab Jamahiriya',
'LI': 'Liechtenstein',
'LT': 'Lithuania',
'LU': 'Luxembourg',
'MO': 'Macao',
'MK': 'Macedonia',
'MG': 'Madagascar',
'MW': 'Malawi',
'MY': 'Malaysia',
'MV': 'Maldives',
'ML': 'Mali',
'MT': 'Malta',
'MH': 'Marshall Islands',
'MQ': 'Martinique',
'MR': 'Mauritania',
'MU': 'Mauritius',
'YT': 'Mayotte',
'MX': 'Mexico',
'FM': 'Micronesia, Federated States Of',
'MD': 'Moldova',
'MC': 'Monaco',
'MN': 'Mongolia',
'ME': 'Montenegro',
'MS': 'Montserrat',
'MA': 'Morocco',
'MZ': 'Mozambique',
'MM': 'Myanmar',
'NA': 'Namibia',
'NR': 'Nauru',
'NP': 'Nepal',
'NL': 'Netherlands',
'AN': 'Netherlands Antilles',
'NC': 'New Caledonia',
'NZ': 'New Zealand',
'NI': 'Nicaragua',
'NE': 'Niger',
'NG': 'Nigeria',
'NU': 'Niue',
'NF': 'Norfolk Island',
'MP': 'Northern Mariana Islands',
'NO': 'Norway',
'OM': 'Oman',
'PK': 'Pakistan',
'PW': 'Palau',
'PS': 'Palestinian Territory, Occupied',
'PA': 'Panama',
'PG': 'Papua New Guinea',
'PY': 'Paraguay',
'PE': 'Peru',
'PH': 'Philippines',
'PN': 'Pitcairn',
'PL': 'Poland',
'PT': 'Portugal',
'PR': 'Puerto Rico',
'QA': 'Qatar',
'RE': 'Reunion',
'RO': 'Romania',
'RU': 'Russian Federation',
'RW': 'Rwanda',
'BL': 'Saint Barthelemy',
'SH': 'Saint Helena',
'KN': 'Saint Kitts And Nevis',
'LC': 'Saint Lucia',
'MF': 'Saint Martin',
'PM': 'Saint Pierre And Miquelon',
'VC': 'Saint Vincent And Grenadines',
'WS': 'Samoa',
'SM': 'San Marino',
'ST': 'Sao Tome And Principe',
'SA': 'Saudi Arabia',
'SN': 'Senegal',
'RS': 'Serbia',
'SC': 'Seychelles',
'SL': 'Sierra Leone',
'SG': 'Singapore',
'SK': 'Slovakia',
'SI': 'Slovenia',
'SB': 'Solomon Islands',
'SO': 'Somalia',
'ZA': 'South Africa',
'GS': 'South Georgia And Sandwich Isl.',
'ES': 'Spain',
'LK': 'Sri Lanka',
'SD': 'Sudan',
'SR': 'Suriname',
'SJ': 'Svalbard And Jan Mayen',
'SZ': 'Swaziland',
'SE': 'Sweden',
'CH': 'Switzerland',
'SY': 'Syrian Arab Republic',
'TW': 'Taiwan',
'TJ': 'Tajikistan',
'TZ': 'Tanzania',
'TH': 'Thailand',
'TL': 'Timor-Leste',
'TG': 'Togo',
'TK': 'Tokelau',
'TO': 'Tonga',
'TT': 'Trinidad And Tobago',
'TN': 'Tunisia',
'TR': 'Turkey',
'TM': 'Turkmenistan',
'TC': 'Turks And Caicos Islands',
'TV': 'Tuvalu',
'UG': 'Uganda',
'UA': 'Ukraine',
'AE': 'United Arab Emirates',
'GB': 'United Kingdom',
'US': 'United States',
'UM': 'United States Outlying Islands',
'UY': 'Uruguay',
'UZ': 'Uzbekistan',
'VU': 'Vanuatu',
'VE': 'Venezuela',
'VN': 'Viet Nam',
'VG': 'Virgin Islands, British',
'VI': 'Virgin Islands, U.S.',
'WF': 'Wallis And Futuna',
'EH': 'Western Sahara',
'YE': 'Yemen',
'ZM': 'Zambia',
'ZW': 'Zimbabwe'
};
export default {
components: {
Table,
},
data() {
return {
columns: [
{ key: "location", label: "Location" },
{ key: "name", label: "Name" },
{ key: "map", label: "Map" },
{ key: "players", label: "Players" },
],
tableData: [],
};
},
methods: {
getData() {
axios
.get(`https://backend.beammp.com/servers-info`)
.then(res => {
var servers = []
var data = res.data;
var i = 0
var serversArray = new Array();
// Parse the data to a nice looking Array
for (var i = 0; i < data.length; i++) {
var v = data[i]
v.strippedName = this.stripCustomFormatting(v.sname);
serversArray.push(v);
}
// Sort the servers to display official servers first
serversArray.sort(function(a, b) {
if (a.official && b.official) return a.strippedName.localeCompare(b.strippedName)
else if (a.official) return -1;
else if (b.official) return 1;
return 0;
});
serversArray.forEach(s => {
servers.push({id: i, cc: s.location, location: this.getCountryName(s.location), name: this.formatServerName(s.sname), map: this.smoothMapName(s.map), players: `${s.players}/${s.maxplayers}`, raw: s, style: this.getRowStyle(s)})
i++
});
this.tableData = servers//res.data
})
},
getRowStyle(server) {
const s = false ? 'rgba(255, 215, 0, 0.35)!important' : server.featured ? 'rgba(0, 128, 0, 0.25)!important' : server.official ? 'rgba(255, 106, 0, 0.25)!important' : server.partner ? 'rgba(0, 123, 195, 0.3)!important' : 'rgba(0, 0, 0, 0)!important';
return `background: ${s}`
},
stripCustomFormatting(name) {
var serverStyleArray = [
"^0",
"^1",
"^2",
"^3",
"^4",
"^5",
"^6",
"^7",
"^8",
"^9",
"^a",
"^b",
"^c",
"^d",
"^e",
"^f",
"^l",
"^m",
"^n",
"^o",
"^r",
"^p"
];
for (var i = 0; i < serverStyleArray.length; i++){
while (name.includes(serverStyleArray[i])){
name = name.replace(serverStyleArray[i], "");
}
}
return name;
},
getCountryName(countryCode) {
if (isoCountries.hasOwnProperty(countryCode)) {
return isoCountries[countryCode];
} else {
return countryCode;
}
},
toTitleCase(str) {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
},
smoothMapName(map) {
if (map != "Any Map") {
map = map.replace("/info.json", "")
map = map.split('/').pop().replace(/\s*/g, '')
map = map.replace(/_/g, " ")
map = map.replace(/-/g, " ")
map = this.toTitleCase(map)
}
return map
},
applyCode(string, codes) {
var cssText = ''
string = string.replace(/\x00*/g, '');
for (var i = 0, len = codes.length; i < len; i++) {
cssText += styleMap[codes[i]] + ';';
}
return {s: string, f:cssText};
},
formatServerName(string) {
var codes = string.match(/\^.{1}/g) || [],
indexes = [],
apply = [],
tmpStr,
name = [],
i,
len;
for (i = 0, len = codes.length; i < len; i++) {
indexes.push(string.indexOf(codes[i]));
string = string.replace(codes[i], '\x00\x00');
}
if (indexes[0] !== 0) {
name.push(this.applyCode(string.substring(0, indexes[0]), []))
}
for (i = 0; i < len; i++) {
var indexDelta = indexes[i + 1] - indexes[i];
if (indexDelta === 2) {
while (indexDelta === 2) {
apply.push(codes[i]);
i++;
indexDelta = indexes[i + 1] - indexes[i];
}
apply.push(codes[i]);
} else {
apply.push(codes[i]);
}
if (apply.lastIndexOf('^r') > -1) {
apply = apply.slice(apply.lastIndexOf('^r') + 1);
}
tmpStr = string.substring(indexes[i], indexes[i + 1]);
name.push(this.applyCode(tmpStr, apply))
}
return name
}
},
beforeMount() {
this.getData()
}
};
</script>
-129
View File
@@ -1,129 +0,0 @@
<template>
<div class="container mx-auto mt-8">
<h1 class="text-4xl font-bold mb-4">Project Metrics</h1>
<!-- Timeseries Graph -->
<div v-if="dataLoaded">
<Plotly :data="graphData" :layout="graphLayout" />
</div>
<!-- Metrics -->
<div class="mt-8">
<p><strong>Concurrent Players (All Time High):</strong> {{ allTimeHigh }}</p>
<p><strong>Players Online Now:</strong> {{ playersOnlineNow }}</p>
<p><strong>Servers Online Now:</strong> {{ serversOnlineNow }}</p>
</div>
</div>
</template>
<script>
import Plotly from '@/components/stats/Plotly.vue'
import axios from 'axios'
export default {
components: {
Plotly,
},
data() {
return {
// Sample Data
graphData: [
{
x: ['2023-01-01', '2023-01-02', '2023-01-03'],
y: [10, 15, 8],
type: 'scatter',
mode: 'lines+markers',
name: 'Concurrent Players',
},
],
graphLayout: {
title: 'Concurrent Players Over Time',
xaxis: {
autorange: true,
range: ['2015-02-17', '2017-02-16'],
rangeselector: {buttons: [
{
count: 24,
label: '24h',
step: 'hour',
stepmode: 'backward'
},
{
count: 7,
label: '7d',
step: 'day',
stepmode: 'backward'
},
{
count: 1,
label: '1m',
step: 'month',
stepmode: 'backward'
},
{
count: 6,
label: '6m',
step: 'month',
stepmode: 'backward'
},
{
count: 12,
label: '1y',
step: 'month',
stepmode: 'backward'
},
{step: 'all'}
]},
rangeslider: {range: ['2015-02-17', '2017-02-16']},
type: 'date'
},
yaxis: {
title: 'Concurrent Players',
autorange: true,
range: [86.8700008333, 138.870004167],
type: 'linear'
}
},
allTimeHigh: 20,
playersOnlineNow: 12,
serversOnlineNow: 3,
dataLoaded: false,
timePeriod: 'today'
};
},
methods: {
setTimeRange(range) {
// Update graph data based on the selected time range
// You need to implement the logic to fetch data from your backend here
console.log(`Updating graph for ${range}`);
},
getData() {
axios
.get(`https://backend.beammp.com/stats-info?period=${this.timePeriod}`)
.then(res => {
const data = [];
var Labels = [];
var Players = [];
if (res.data.v2history) {
res.data.v2history.forEach(function(item, index) {
Labels.push(item.datetime)
Players.push(item.players)
})
this.graphData[0].x = Labels
this.graphData[0].y = Players
this.allTimeHigh = res.data.maxp
console.log('Data Downloaded & Sorted')
this.dataLoaded = true
}
})
}
},
beforeMount() {
this.getData();
},
};
</script>
<style scoped>
/* Add Tailwind CSS styles as needed */
</style>
-3
View File
@@ -1,3 +0,0 @@
<template>
<h1>BeamMP Terms & Conditions</h1>
</template>
-26
View File
@@ -1,26 +0,0 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
colors: {
"beammp-orange": '#f36d24',
"beammp-white": '#ffffff',
"beammp-black": '#000000',
"beammp-gray": '#333333',
"beammp-green": '#1d9749',
"beammp-blue": '4470b6'
},
fontFamily: {
sans: [
'"Noto Sans"',
],
serif: ['Merriweather', 'serif'],
},
extend: {},
},
plugins: [],
}
+560
View File
@@ -0,0 +1,560 @@
<!doctype html>
<html lang="en" style="overflow-x: hidden;">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/ico+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BeamMP - Multiplayer for BeamNG.drive</title>
<meta name="description"
content="BeamMP is a multiplayer mod for BeamNG.drive. Join thousands of players online and experience BeamNG.drive with friends!">
</head>
<body>
<!-- Vue App Container (shown when JS is enabled) -->
<div id="app"></div>
<!-- No-JS Fallback (shown when JS is disabled) -->
<noscript>
<style>
/* CSS Variables for Light/Dark Theme */
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #1a1a1a;
--text-secondary: #666666;
--border-color: #e5e5e5;
--beammp-blue: #4470B6;
--beammp-orange: #F36D24;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #1a1a1a;
--bg-secondary: #2a2a2a;
--text-primary: #ffffff;
--text-secondary: #a0a0a0;
--border-color: rgba(255, 255, 255, 0.1);
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background-color: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* Header/Navigation */
header {
border-bottom: 1px solid var(--border-color);
background-color: var(--bg-primary);
position: sticky;
top: 0;
z-index: 100;
backdrop-filter: blur(10px);
}
nav {
display: flex;
align-items: center;
justify-content: space-between;
height: 4rem;
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
.logo img {
height: 4rem;
width: auto;
}
@media (prefers-color-scheme: dark) {
.logo-light {
display: none;
}
.logo-dark {
display: block;
}
}
@media (prefers-color-scheme: light) {
.logo-light {
display: block;
}
.logo-dark {
display: none;
}
}
.nav-links {
display: flex;
gap: 1.5rem;
list-style: none;
flex-wrap: wrap;
align-items: center;
}
.nav-links a {
color: var(--text-primary);
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
transition: background-color 0.2s;
}
.nav-links a:hover {
background-color: var(--bg-secondary);
}
/* Hero Section */
.hero {
text-align: center;
padding: 4rem 1rem;
background: linear-gradient(135deg, var(--beammp-blue) 0%, var(--beammp-orange) 100%);
color: white;
}
.hero h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
}
.hero p {
font-size: 1.25rem;
margin-bottom: 2rem;
opacity: 0.95;
}
.cta-button {
display: inline-block;
background-color: white;
color: var(--beammp-blue);
padding: 0.875rem 2rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
}
.cta-button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
/* Stats Section */
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
padding: 3rem 1rem;
background-color: var(--bg-secondary);
}
.stat-card {
text-align: center;
padding: 2rem;
background-color: var(--bg-primary);
border-radius: 0.5rem;
border: 1px solid var(--border-color);
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: var(--beammp-blue);
margin-bottom: 0.5rem;
}
.stat-label {
color: var(--text-secondary);
font-size: 1rem;
}
/* Features Section */
.features {
padding: 4rem 1rem;
}
.section-title {
text-align: center;
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 3rem;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 2rem;
}
.feature-card {
padding: 2rem;
border: 1px solid var(--border-color);
border-radius: 0.5rem;
background-color: var(--bg-primary);
}
.feature-icon {
width: 3rem;
height: 3rem;
margin-bottom: 1rem;
color: var(--beammp-blue);
}
.feature-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.75rem;
}
.feature-description {
color: var(--text-secondary);
}
/* Info Section */
.info {
padding: 4rem 1rem;
background-color: var(--bg-secondary);
}
.info-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.info-content h2 {
font-size: 2rem;
margin-bottom: 1.5rem;
}
.info-content p {
font-size: 1.125rem;
color: var(--text-secondary);
margin-bottom: 2rem;
}
.button-group {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.button {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: 500;
transition: transform 0.2s;
}
.button-primary {
background-color: var(--beammp-blue);
color: white;
}
.button-secondary {
background-color: var(--bg-primary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.button:hover {
transform: translateY(-2px);
}
/* Footer */
footer {
margin-top: auto;
padding: 2rem 1rem;
border-top: 1px solid var(--border-color);
background-color: var(--bg-primary);
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 2rem;
}
.social-links {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
align-items: center;
}
.social-link {
color: var(--text-secondary);
transition: color 0.2s;
text-decoration: none;
}
.social-link:hover {
color: var(--beammp-blue);
}
.footer-legal {
text-align: center;
color: var(--text-secondary);
font-size: 0.875rem;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.footer-links a {
color: var(--text-secondary);
text-decoration: none;
}
.footer-links a:hover {
color: var(--beammp-blue);
}
/* Responsive */
@media (max-width: 768px) {
.hero h1 {
font-size: 2rem;
}
.hero p {
font-size: 1rem;
}
.nav-links {
display: none;
}
.section-title {
font-size: 2rem;
}
}
/* JS Warning */
.js-notice {
background-color: #fff3cd;
color: #856404;
padding: 1rem;
text-align: center;
font-weight: 500;
}
@media (prefers-color-scheme: dark) {
.js-notice {
background-color: #664d03;
color: #ffecb5;
}
}
/* Hide noscript content when JS loads */
.noscript-page {
display: block;
}
/* SVG Icons */
.icon {
width: 1.5rem;
height: 1.5rem;
display: inline-block;
vertical-align: middle;
}
</style>
<div class="noscript-page">
<!-- Header -->
<header>
<nav>
<a href="/" class="logo">
<img src="/src/assets/BeamMP_blk.png" alt="BeamMP Logo" class="logo-light">
<img src="/src/assets/BeamMP_wht.png" alt="BeamMP Logo" class="logo-dark">
</a>
<ul class="nav-links">
<li><a href="https://forum.beammp.com">Forums</a></li>
<li><a href="https://docs.beammp.com">Docs</a></li>
<li><a href="https://github.com/BeamMP/BeamMP">GitHub</a></li>
<li><a href="https://www.patreon.com/BeamMP">Patreon</a></li>
</ul>
</nav>
</header>
<!-- JS Notice -->
<div class="js-notice">
⚠️ JavaScript is disabled. For the best experience, please enable JavaScript in your browser.
</div>
<!-- Hero Section -->
<section class="hero">
<div class="container">
<h1>BeamMP</h1>
<p>Multiplayer for BeamNG.drive</p>
<a href="https://github.com/BeamMP/BeamMP/releases" class="cta-button">
Download Now
</a>
</div>
</section>
<!-- Stats Section -->
<section class="container stats">
<div class="stat-card">
<div class="stat-number">2000+</div>
<div class="stat-label">Online Players</div>
</div>
<div class="stat-card">
<div class="stat-number">3000+</div>
<div class="stat-label">Active Servers</div>
</div>
<div class="stat-card">
<div class="stat-number">100%</div>
<div class="stat-label">Certified Fun!</div>
</div>
</section>
<!-- Features Section -->
<section class="features">
<div class="container">
<h2 class="section-title">Why Choose BeamMP?</h2>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="20" height="8" x="2" y="2" rx="2" ry="2" />
<rect width="20" height="8" x="2" y="14" rx="2" ry="2" />
<line x1="6" x2="6.01" y1="6" y2="6" />
<line x1="6" x2="6.01" y1="18" y2="18" />
</svg>
</div>
<h3 class="feature-title">Stable & Reliable</h3>
<p class="feature-description">Enjoy smooth multiplayer gameplay with our optimized server infrastructure.
</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20.2 7.8l-7.7 7.7-4-4-5.7 5.7" />
<path d="M15 7h6v6" />
</svg>
</div>
<h3 class="feature-title">Easy to Use</h3>
<p class="feature-description">Simple installation and setup process. Get playing within minutes!</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
<path d="M2 12h20" />
</svg>
</div>
<h3 class="feature-title">Global Community</h3>
<p class="feature-description">Join thousands of players worldwide in various game modes and communities.
</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
</div>
<h3 class="feature-title">Mod Support</h3>
<p class="feature-description">Create custom servers with Lua scripting and mod support.</p>
</div>
</div>
</div>
</section>
<!-- Info Section -->
<section class="info">
<div class="container">
<div class="info-content">
<h2>Get Started Today</h2>
<p>BeamMP is completely free and open source. Download the mod, join a server, and start playing with
friends!</p>
<div class="button-group">
<a href="https://github.com/BeamMP/BeamMP/releases" class="button button-primary">Download</a>
<a href="https://docs.beammp.com" class="button button-secondary">Documentation</a>
<a href="https://forum.beammp.com" class="button button-secondary">Forums</a>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer>
<div class="footer-content">
<div class="social-links">
<a href="https://github.com/BeamMP" class="social-link" aria-label="GitHub">GitHub</a>
<span>•</span>
<a href="https://discord.gg/beammp" class="social-link" aria-label="Discord">Discord</a>
<span>•</span>
<a href="https://www.youtube.com/@beammpofficial" class="social-link" aria-label="YouTube">YouTube</a>
<span>•</span>
<a href="https://x.com/beammpofficial" class="social-link" aria-label="X">X</a>
<span>•</span>
<a href="https://www.reddit.com/r/BeamMP" class="social-link" aria-label="Reddit">Reddit</a>
<span>•</span>
<a href="https://www.patreon.com/BeamMP" class="social-link" style="color: var(--beammp-orange);">Support on
Patreon</a>
</div>
<div class="footer-legal">
<p>&copy; 2019 - 2025 | BeamMP Mod Team All Rights Reserved</p>
<div class="footer-links">
<a href="https://forum.beammp.com/topic/95/privacy-policy-v1-0">Privacy Policy</a>
<span>•</span>
<a href="https://forum.beammp.com/topic/94/terms-of-use-v1-0">Terms of Use</a>
</div>
</div>
</div>
</footer>
</div>
</noscript>
<!-- Vue.js Application Script -->
<script type="module" src="/src/main.js"></script>
<!-- Hide noscript content when JS is available -->
<script>
// Hide noscript content as soon as JS executes
document.addEventListener('DOMContentLoaded', function () {
const noscriptDivs = document.querySelectorAll('.noscript-page');
noscriptDivs.forEach(div => div.style.display = 'none');
});
</script>
</body>
</html>
-93
View File
@@ -1,93 +0,0 @@
#!/usr/bin/env node
/*
* oooooooooo. ooo ooooo ooooooooo.
* `888' `Y8b `88. .888' `888 `Y88.
* 888 888 .ooooo. .oooo. ooo. .oo. .oo. 888b d'888 888 .d88'
* 888oooo888' d88' `88b `P )88b `888P"Y88bP"Y88b 8 Y88. .P 888 888ooo88P'
* 888 `88b 888ooo888 .oP"888 888 888 888 8 `888' 888 888
* 888 .88P 888 .o d8( 888 888 888 888 8 Y 888 888
* o888bood8P' `Y8bod8P' `Y888""8o o888o o888o o888o o8o o888o o888o
* ========================================================================
* Copyright (c) 2019-2023 BeamMP Ltd. All rights reserved.
*/
require('dotenv').config()
const pkg = require('./package.json')
const chalk = require('chalk');
const cluster = require('cluster');
const error = chalk.bold.keyword('red');
const warn = chalk.keyword('orange');
const good = chalk.keyword('lime');
process.on('warning', (warning) => {
console.log(warning.stack);
});
if (cluster.isMaster) {
const env = process.env.NODE_ENV || 'development'
console.log('oooooooooo. ooo ooooo ooooooooo. ')
console.log('`888\' `Y8b `88. .888\' `888 `Y88. ')
console.log(' 888 888 .ooooo. .oooo. ooo. .oo. .oo. 888b d\'888 888 .d88\' ')
console.log(' 888oooo888\' d88\' `88b `P )88b `888P"Y88bP"Y88b 8 Y88. .P 888 888ooo88P\' ')
console.log(' 888 `88b 888ooo888 .oP"888 888 888 888 8 `888\' 888 888 ')
console.log(' 888 .88P 888 .o d8( 888 888 888 888 8 Y 888 888 ')
console.log('o888bood8P\' `Y8bod8P\' `Y888""8o o888o o888o o888o o8o o888o o888o ')
console.log('=================================================================================')
console.log('Website v' + pkg.version + ' Copyright (C) 2019-2024 BeamMP Ltd')
console.log('')
console.log('Running in: ' + env)
console.log('Server Time: ' + new Date())
function start() {
process.title = pkg.name + "@" + pkg.version;
if (cluster.isMaster) {
console.log(`Master PID: ${process.pid}`)
console.log(`Creating ${process.env.INSTANCES} Instances of the Website Backend`)
for (let i = 0; i < process.env.INSTANCES; i++) {
cluster.fork();
}
// set console's directory so we can see output from workers
console.dir(cluster.workers, { depth: 0 });
cluster.on('exit', (worker, code) => {
// Good exit code is 0 :))
// exitedAfterDisconnect ensures that it is not killed by master cluster or manually
// if we kill it via .kill or .disconnect it will be set to true
// \x1b[XXm represents a color, and [0m represent the end of this
//color in the console ( 0m sets it to white again )
if (code !== 0 && !worker.exitedAfterDisconnect) {
console.error(`\x1b[34mWorker ${worker.process.pid} crashed... Starting a new worker...\x1b[0m`);
const nw = cluster.fork();
console.error(`\x1b[32mWorker ${nw.process.pid} will replace him \x1b[0m`);
}
});
} else {
console.error('FATAL: This script can only be run as a master process.')
}
}
start()
} else {
const ws = require('./src/webserver')
try {
ws.init(function (err) {
if (err) {
console.error(err)
return
}
ws.listen(function () {
console.info('BeamMP Website Ready')
})
})
} catch (e) {
throw e;
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
+22
View File
@@ -0,0 +1,22 @@
server {
listen 80;
server_name _;
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;
}
# 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;
access_log off;
}
}
+3151 -1291
View File
File diff suppressed because it is too large. Load diff
+31 -22
View File
@@ -1,29 +1,38 @@
{ {
"name": "beammp-website", "name": "beammp-website",
"version": "1.0.1", "private": true,
"description": "BeamMP Website", "version": "2.1.0",
"main": "index.js", "type": "module",
"scripts": { "scripts": {
"docker-build": "docker build -t 192.168.100.6:5000/beammp/website:latest -t 192.168.100.6:5000/beammp/website:1.0.1 .", "dev": "vite",
"docker-push": "docker push 192.168.100.6:5000/beammp/website:latest" "build": "vite build",
"preview": "vite preview",
"lint": "eslint . --fix",
"format": "prettier --write \"src/**/*.{js,vue,css,json}\""
}, },
"repository": {
"type": "git",
"url": "git+https://github.com/BeamMP/BeamMP-Website.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/BeamMP/BeamMP-Website/issues"
},
"homepage": "https://github.com/BeamMP/BeamMP-Website#readme",
"dependencies": { "dependencies": {
"body-parser": "^1.19.0", "@tailwindcss/vite": "^4.1.17",
"chalk": "^3.0.0", "@vueuse/core": "^14.1.0",
"dotenv": "^16.0.3", "class-variance-authority": "^0.7.1",
"ejs": "^3.0.1", "clsx": "^2.1.1",
"express": "^4.17.1", "lucide-vue-next": "^0.555.0",
"helmet": "^6.1.5", "reka-ui": "^2.6.0",
"morgan": "^1.10.0" "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tailwindcss-animate": "^1.0.7",
"vue": "^3.5.25",
"vue-i18n": "^11.2.2",
"vue-router": "^4.6.3"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.2",
"@vue/eslint-config-prettier": "^10.2.0",
"eslint": "^9.39.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-vue": "^10.6.2",
"prettier": "^3.7.3",
"tw-animate-css": "^1.4.0",
"vite": "^7.2.4"
} }
} }
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 372 files, more files were not shown because too many files have changed in this diff. Show more