A ton of frontend.

- Added basic blog layout and routes.

- Basic games frontend.

- Basic frontend for admin site configuration.

- User profiles.

- User last online dates.

- Fixed performance issues with CPU and memory usage counters. They are now queued events that update their respective rows in the database every minute.

- Renamed "graphictoria-item-page" css class to "graphictoria-smaller-page".

- Added screenshots that some images were based on.
This commit is contained in:
Graphictoria 2022-10-01 00:20:48 -04:00
parent ac65f02703
commit ed3cef5057
37 changed files with 693 additions and 52 deletions

View File

@ -1,10 +1,16 @@
# Allow read in the public directories.
<Directory "C:/graphictoria/COMMIT_HASH/web/public/">
Require local
Require all granted
AllowOverride All
</Directory>
<Directory "C:/graphictoria/COMMIT_HASH/web/public_api/">
Require local
Require all granted
AllowOverride All
</Directory>
# Disallow access to admin JS
<Directory "C:/graphictoria/COMMIT_HASH/web/public/js/adm/">
Require all denied
AllowOverride All
</Directory>
@ -14,15 +20,14 @@
ServerName gtoria.net
ServerAlias www.gtoria.net
ServerAlias wiki.gtoria.net
SSLEngine on
SSLCertificateFile "C:/graphictoria/COMMIT_HASH/etc/cert/localhost.crt"
SSLCertificateKeyFile "C:/graphictoria/COMMIT_HASH/etc/cert/localhost.key"
SSLCertificateFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.crt"
SSLCertificateKeyFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.key"
ErrorLog "C:/graphictoria/logs/gt-test-error.log"
ErrorLog "C:/graphictoria/logs/gt-error.log"
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Host}i\" \"%{Referer}i\" \"%{User-agent}i\"" gtoria
CustomLog "C:/graphictoria/logs/gt-test-access.log" gtoria
CustomLog "C:/graphictoria/logs/gt-access.log" gtoria
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
@ -31,7 +36,28 @@
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
DocumentRoot "D:/wamp320/graphictoria/sitetest3/web/public"
DocumentRoot "C:/graphictoria/COMMIT_HASH/web/public"
</VirtualHost>
# Blog/Wiki
<VirtualHost *:80 *:443>
ServerName gtoria.net
ServerAlias blog.gtoria.net
ServerAlias wiki.gtoria.net
SSLEngine on
SSLCertificateFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.crt"
SSLCertificateKeyFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.key"
ErrorLog "C:/xampp/logs/gt-error.log"
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Host}i\" \"%{Referer}i\" \"%{User-agent}i\"" gtoria
CustomLog "C:/xampp/logs/gt-access.log" gtoria
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
DocumentRoot "C:/graphictoria/COMMIT_HASH/web/public"
</VirtualHost>
# Api endpoints.
@ -49,12 +75,12 @@
ServerAlias test.public.ecs.gtoria.net
SSLEngine on
SSLCertificateFile "C:/graphictoria/COMMIT_HASH/etc/cert/localhost.crt"
SSLCertificateKeyFile "C:/graphictoria/COMMIT_HASH/etc/cert/localhost.key"
SSLCertificateFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.crt"
SSLCertificateKeyFile "C:/graphictoria/COMMIT_HASH/etc/cert/cloudflare.key"
ErrorLog "C:/graphictoria/logs/gt-test-error.log"
ErrorLog "C:/graphictoria/logs/gt-error.log"
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Host}i\" \"%{Referer}i\" \"%{User-agent}i\"" gtoria
CustomLog "C:/graphictoria/logs/gt-test-access.log" gtoria
CustomLog "C:/graphictoria/logs/gt-access.log" gtoria
DocumentRoot "D:/wamp320/graphictoria/sitetest3/web/public_api"
DocumentRoot "C:/graphictoria/COMMIT_HASH/web/public_api"
</VirtualHost>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

View File

@ -5,6 +5,8 @@ namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Jobs\UpdateUsageCounters;
class Kernel extends ConsoleKernel
{
/**
@ -15,7 +17,7 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
$schedule->job(new UpdateUsageCounters)->everyMinute();
}
/**

View File

@ -7,6 +7,8 @@
namespace App\Helpers;
use App\Models\UsageCounter;
class QAaMBHelper
{
public static function wmiWBemLocatorQuery($query)
@ -78,31 +80,29 @@ class QAaMBHelper
public static function getSystemCpuInfo($output_key = '')
{
return cache()->remember('QAaMB-Cpu-Info', 5, function(){
$result = 0;
$result = 0;
try {
if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') {
// LINUX
return sys_getloadavg();
} else {
// WINDOWS
$wmi_found = false;
if ( $wmi_query = self::wmiWBemLocatorQuery(
"SELECT LoadPercentage FROM Win32_Processor" ) ) {
foreach($wmi_query as $r) {
$result = $r->LoadPercentage / 100;
$wmi_found = true;
}
try {
if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') {
// LINUX
return sys_getloadavg();
} else {
// WINDOWS
$wmi_found = false;
if ( $wmi_query = self::wmiWBemLocatorQuery(
"SELECT LoadPercentage FROM Win32_Processor" ) ) {
foreach($wmi_query as $r) {
$result = $r->LoadPercentage / 100;
$wmi_found = true;
}
}
} catch(Exception $e) {
echo $e->getMessage();
}
return empty($output_key) || !isset($result[$output_key]) ? $result : $result[$output_key];
});
} catch(Exception $e) {
echo $e->getMessage();
}
return empty($output_key) || !isset($result[$output_key]) ? $result : $result[$output_key];
}
public static function memoryString($memory)
@ -113,7 +113,7 @@ class QAaMBHelper
public static function getMemoryUsage()
{
$memoryInfo = self::getSystemMemoryInfo();
$memoryInfo = json_decode(UsageCounter::where('name', 'Memory')->first()->value, true);
// XlXi: the -2 is required so it fits inside of the bar thing
// XlXi: change this if theres ever a separate graph
@ -128,18 +128,27 @@ class QAaMBHelper
public static function getMemoryPercentage()
{
$memoryInfo = self::getSystemMemoryInfo();
$memoryInfo = json_decode(UsageCounter::where('name', 'Memory')->first()->value, true);
return ($memoryInfo['MemTotal'] - $memoryInfo['MemFree']) / $memoryInfo['MemTotal'];
}
public static function getCpuUsage()
{
$cpuInfo = UsageCounter::where('name', 'CPU')->first();
// XlXi: the -2 is required so it fits inside of the bar thing
// XlXi: change this if theres ever a separate graph
return sprintf(
'%s%% CPU Usage',
round(self::getSystemCpuInfo() * (100-2))
round(floatval($cpuInfo->value) * (100-2))
);
}
public static function getCpuPercentage()
{
$cpuInfo = UsageCounter::where('name', 'CPU')->first();
return $cpuInfo->value;
}
}

View File

@ -2,9 +2,11 @@
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\DynamicWebConfiguration;
class AdminController extends Controller
{
// Moderator+
@ -30,4 +32,11 @@ class AdminController extends Controller
'arbiter' => $arbiterType
]);
}
function configuration(Request $request)
{
return view('web.admin.configuration')->with([
'values' => DynamicWebConfiguration::get()
]);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class GamesController extends Controller
{
public function index()
{
return view('web.games.index');
}
}

View File

@ -39,9 +39,10 @@ class Kernel extends HttpKernel
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// Yeah no, the double session protector was stupid.
// XlXi: Yeah no, the double session protector was stupid.
//\App\Http\Middleware\DoubleSessionProtector::class, // Prevents DDoS attacks.
\App\Http\Middleware\DailyReward::class
\App\Http\Middleware\DailyReward::class,
\App\Http\Middleware\LastSeenMiddleware::class
],
'api' => [
@ -71,5 +72,6 @@ class Kernel extends HttpKernel
'roleset' => \App\Http\Middleware\Roleset::class,
'banned' => \App\Http\Middleware\CheckBan::class,
'lastseen' => \App\Http\Middleware\LastSeenMiddleware::class,
];
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Middleware;
use Carbon\Carbon;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LastSeenMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if(Auth::check()) {
$user = Auth::user();
$user->last_seen = Carbon::now();
$user->timestamps = false;
$user->save();
}
return $next($request);
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Helpers\QAaMBHelper;
use App\Models\UsageCounter;
class UpdateUsageCounters implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$memoryInfo = QAaMBHelper::getSystemMemoryInfo();
$cpuInfo = QAaMBHelper::getSystemCpuInfo();
UsageCounter::where('name', 'CPU')->update([ 'value' => $cpuInfo ]);
UsageCounter::where('name', 'Memory')->update([ 'value' => $memoryInfo ]);
}
}

View File

@ -2,10 +2,66 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class DynamicWebConfiguration extends Model
{
use HasFactory;
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'masked' => 'boolean'
];
public function getTruncatedValue($value = null)
{
if($value == null)
$value = $this->value;
if(strlen($value) < 50)
return $value;
return (substr($value, 0, 50) . '...');
}
public function getJumbledValue()
{
$letters = 'abcdefghijklmnopqrstuvwxyz0123456789 `~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?';
$result = '';
for($i=0; strlen($this->value) > $i; $i++)
$result .= $letters[rand(0, strlen($letters)-1)];
return $this->getTruncatedValue($result);
}
public function getCreated()
{
$date = $this['created_at'];
if(Carbon::now()->greaterThan($date->copy()->addDays(2)))
$date = $date->isoFormat('lll');
else
$date = $date->calendar();
return $date;
}
public function getUpdated()
{
$date = $this['updated_at'];
if(Carbon::now()->greaterThan($date->copy()->addDays(2)))
$date = $date->isoFormat('lll');
else
$date = $date->calendar();
return $date;
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class UsageCounter extends Model
{
use HasFactory;
}

View File

@ -2,6 +2,7 @@
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
@ -47,6 +48,7 @@ class User extends Authenticatable implements MustVerifyEmail
protected $casts = [
'email_verified_at' => 'datetime',
'next_reward' => 'datetime',
'last_seen' => 'datetime',
];
/**
@ -73,12 +75,39 @@ class User extends Authenticatable implements MustVerifyEmail
return route('user.profile', ['user' => $this->id]);
}
public function getLastSeen()
{
if($this->last_seen >= Carbon::now()->subMinutes(2))
return 'Now';
if(Carbon::now() >= $this->last_seen->copy()->addDays(2))
return $this->last_seen->isoFormat('ll');
else
return $this->last_seen->calendar();
}
public function getJoinDate()
{
return $this->created_at->isoFormat('ll');
}
// XlXi: Returns a class name like text-success or
// gt-status-studio to show next to the
// user's name.
public function getOnlineClass()
{
if($this->last_seen >= Carbon::now()->subMinutes(2))
return 'text-success';
return 'text-muted';
}
public function _hasRolesetInternal($roleName)
{
$roleset = Roleset::where('Name', $roleName)->first();
if(
UserRoleset::where('Roleset_id', $roleset->id)
->where('User_id', Auth::user()->id)
->where('User_id', $this->id)
->exists()
)
return true;

View File

@ -47,6 +47,14 @@ class RouteServiceProvider extends ServiceProvider
->namespace('App\Http\Controllers\Web')
->group(base_path('routes/web.php'));
//
// Domain: www.gtoria.net
//
Route::domain('blog.' . DomainHelper::TopLevelDomain())
->middleware('web')
->namespace('App\Http\Controllers\Blog')
->group(base_path('routes/blog.php'));
//
// Domain: api.gtoria.net
//

View File

@ -28,6 +28,7 @@ return new class extends Migration
$table->string('thumbnail2DHash')->nullable();
$table->string('thumbnail3DHash')->nullable();
$table->dateTime('last_seen')->useCurrent();
$table->timestamps();
});
}

View File

@ -17,6 +17,7 @@ return new class extends Migration
$table->id();
$table->string('name');
$table->string('value');
$table->boolean('masked')->default(false);
$table->timestamps();
});
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('usage_counters', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('value');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('usage_counters');
}
};

View File

@ -15,9 +15,10 @@ class DatabaseSeeder extends Seeder
public function run()
{
$this->call([
//FFlagSeeder::class,
WebConfigurationSeeder::class,
UsageCounterSeeder::class,
RolesetSeeder::class
//FFlagSeeder::class
]);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\UsageCounter;
class UsageCounterSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
UsageCounter::create([
'name' => 'CPU',
'value' => '1'
]);
UsageCounter::create([
'name' => 'Memory',
'value' => '{"MemTotal":32768,"MemFree":1}'
]);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -5,12 +5,16 @@
import $ from 'jquery';
import * as Bootstrap from 'bootstrap';
import axios from 'axios';
import React from 'react';
import { render } from 'react-dom';
import { buildGenericApiUrl } from '../util/HTTP.js';
import SearchBar from './SearchBar';
axios.defaults.withCredentials = true;
const searchBarId = 'graphictoria-nav-searchbar';
$(document).ready(function() {
@ -24,4 +28,8 @@ $(document).ready(function() {
}
window.Bootstrap = Bootstrap;
});
});
setInterval(function(){
axios.get(buildGenericApiUrl('api', 'ping'))
}, 120000)

View File

@ -0,0 +1,29 @@
/*
Graphictoria 5 (https://gtoria.net)
Copyright © XlXi 2022
*/
import $ from 'jquery';
const configId = 'gt-config-values';
$(document).ready(function() {
if (document.getElementById(configId)) {
let configItems = document.getElementById(configId).children;
let items = [];
for(let i = 0; i < configItems.length; i++) {
let item = configItems[i];
items.push({
id: item.getAttribute('data-id'),
name: item.getAttribute('data-name'),
isMasked: (item.getAttribute('data-is-masked') === '1'),
value: item.getAttribute('data-value'),
created: item.getAttribute('data-created'),
updated: item.getAttribute('data-updated')
});
}
console.log(items);
}
});

View File

@ -73,7 +73,7 @@ img.twemoji {
height: 420px;
}
.graphictoria-item-page {
.graphictoria-smaller-page {
max-width: 1096px;
margin: 0 auto 0 auto;
}
@ -368,6 +368,16 @@ html {
background-position: center;
}
.graphictoria-blog {
/* XlXi: I LOVE CSS I LOVE CSS I LOVE CSS I LOVE CSS I LOVE CSS I LOVE CSS */
background-image: url("/Images/Backgrounds/Blog.png")!important;
background-size: cover!important;
background-repeat: no-repeat!important;
background-position: center!important;
height: 330px;
background: #141414;
}
// Home Page
.graphictoria-homepage-header {

View File

@ -0,0 +1,40 @@
@php
$slogan = (View::hasSection('description') ? View::getSection('description') . ' ' : '') . 'Graphictoria is an online social platform for those looking to relive the classic Roblox experience. So what are you waiting for? Join 8k+ other users in reliving the good ol\' days! Graphictoria is not affiliated with or sponsored by Roblox Corporation, all Roblox related indica and slogans belong to Roblox Corporation.';
@endphp
<!DOCTYPE html>
<html class="gtoria-dark" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<title>Graphictoria Blog{{ View::hasSection('title') ? ' | ' . View::getSection('title') : '' }}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#348AFF"/>
<meta name="author" content="Graphictoria"/>
<meta name="description" content="{{ $slogan }}"/>
<meta name="keywords" content="graphictoria, xdiscuss, nostalgia, roblox, gtoria, private server, classic, old roblox, classic roblox, forum, game engine, mmo, classic mmo, old internet"/>
<meta property="og:title" content="Graphictoria Blog{{ View::hasSection('title') ? ' | ' . View::getSection('title') : '' }}"/>
<meta property="og:site_name" content="Graphictoria Blog"/>
<meta property="og:description" content="{{ $slogan }}"/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="{{ asset('images/banner.png') }}">
<meta name="twitter:image" content="{{ asset('images/banner.png') }}">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="twitter:card" content="summary_large_image">
@once
<link href="{{ asset('favicon.ico') }}" rel="icon" integrity="{{ Sri::hash('favicon.ico') }}" crossorigin="anonymous" />
<link href="{{ asset('images/logo.png') }}" rel="apple-touch-icon" integrity="{{ Sri::hash('images/logo.png') }}" crossorigin="anonymous" />
<link href="{{ mix('css/Graphictoria.css') }}" rel="stylesheet" integrity="{{ Sri::hash('css/graphictoria.css') }}" crossorigin="anonymous" />
<script src="{{ mix('js/app.js') }}" integrity="{{ Sri::hash('js/app.js') }}" crossorigin="anonymous"></script>
@endonce
@yield('extra-headers')
@yield('page-specific')
</head>
<body>
<div id="gtoria-root">
@include('layouts.blog.nav')
@yield('content')
@include('layouts.footer')
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
<div class="container graphictoria-smaller-page fixed-top">
<div class="navbar navbar-expand-lg graphictoria-navbar rounded m-2">
<div class="container-fluid px-4">
<a class="navbar-brand" href="/">
<img src="{{ asset('/images/logo.png') }}" alt="Graphictoria" width="43" height="43" draggable="false"/>
&nbsp;Blog
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#graphictoria-nav" aria-controls="graphictoria-nav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-md-center" id="graphictoria-nav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" href="{{ url('/') }}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url('/') }}">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://gtoria.net">Main Site</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="graphictoria-blog shadow-sm"></div>

View File

@ -25,7 +25,14 @@
"label" => "Blog",
"location" => 'https://blog.gtoria.net'
],
]
];
if(str_starts_with(request()->getHost(), 'blog.')) {
foreach($routes as $key => $route) {
if($route['label'] == 'Blog')
array_splice($routes, $key, $key);
}
}
@endphp
<div class="footer mt-auto pt-3 text-center shadow-lg">

View File

@ -76,7 +76,7 @@
<a href="{{ route('admin.dashboard') }}" class="nav-link py-0"><i class="fa-solid fa-gavel"></i></a>
</li>
@admin
<li class="nav-item" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true" title="<strong>Only accurate at page load</strong><br/>{{ \App\Helpers\QAaMBHelper::getMemoryUsage() }}">
<li class="nav-item" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true" title="<strong>Updates every minute</strong><br/>{{ \App\Helpers\QAaMBHelper::getMemoryUsage() }}">
<span class="px-md-2 d-flex" style="height:24px;">
<div class="my-auto rounded-1 bg-secondary border border-light right-0 me-1 position-relative graphictoria-admin-memorybar">
@php
@ -98,12 +98,12 @@
<i class="my-auto fa-solid fa-gear"></i>
</span>
</li>
<li class="nav-item" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true" title="<strong>Only accurate at page load</strong><br/>{{ \App\Helpers\QAaMBHelper::getCpuUsage() }}">
<li class="nav-item" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true" title="<strong>Updates every minute</strong><br/>{{ \App\Helpers\QAaMBHelper::getCpuUsage() }}">
<span class="px-md-2 d-flex" style="height:24px;">
<div class="my-auto rounded-1 bg-secondary border border-light right-0 me-1 position-relative graphictoria-admin-memorybar">
@php
$admin_cpubar_color = 'bg-primary';
$admin_cpubar_usage = \App\Helpers\QAaMBHelper::getSystemCpuInfo() * 100;
$admin_cpubar_usage = \App\Helpers\QAaMBHelper::getCpuPercentage() * 100;
if($admin_cpubar_usage <= 25)
$admin_cpubar_color = 'bg-success'; // Green

View File

@ -0,0 +1,72 @@
@extends('layouts.admin')
@section('title', 'Site Configuration')
@section('page-specific')
<style>
.gt-small-row {
width: 0;
text-align: center;
}
.gt-masked-text {
filter: blur(3px);
}
.gt-masked-text-shown {
color: red;
}
</style>
<!-- Secure Page JS -->
<script src="data:text/javascript;base64,{{ base64_encode(File::get(public_path('js/adm/SiteConfiguration.js'))) }}"></script>
@endsection
@push('content')
<div class="container-md">
<h4>Site Configuration</h4>
<div class="card p-2">
<table class="table table-sm table-bordered table-striped mb-2">
<thead>
<tr>
<th>ID</th>
<th>Actions</th>
<th>Name</th>
<th>Value</th>
<th>Created</th>
<th>Modified</th>
</tr>
</thead>
<tbody id="gt-config-values">
@foreach($values as $conf)
@php
$confValue = ($conf->masked ? $conf->getJumbledValue() : $conf->getTruncatedValue())
@endphp
<tr
data-id="{{ $conf->id }}"
data-name="{{ $conf->name }}"
data-is-masked="{{ $conf->masked }}"
data-value="{{ $confValue }}"
data-created="{{ $conf->getCreated() }}"
data-updated="{{ $conf->getUpdated() }}"
>
<th class="gt-small-row">{{ $conf->id }}</th>
<td class="gt-small-row"><button class="btn btn-sm btn-primary" disabled>Edit</button></td>
<td>{{ $conf->name }}</td>
<td @class(['d-flex' => $conf->masked])>
@if($conf->masked)
<span class="gt-masked-text">{{ $confValue }}</span>
<button class="ms-auto btn btn-sm btn-danger" disabled>Unmask</button>
@else
{{ $confValue }}
@endif
</td>
<td>{{ $conf->getCreated() }}</td>
<td>{{ $conf->getUpdated() }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endpush

View File

@ -0,0 +1,10 @@
@extends('layouts.app')
@section('title', 'Games')
@section('content')
<div id="gt-games-main" class="container-lg my-2 d-flex flex-column">
<h4 class="my-auto">Games</h4>
<x-loader />
</div>
@endsection

View File

@ -38,7 +38,7 @@
@if(!$asset->approved)
<div class="alert alert-danger text-center"><strong>This asset is pending approval.</strong> It will not appear in-game and cannot be voted on or purchased at this time.</div>
@endif
<div id="gt-item" class="graphictoria-item-page"
<div id="gt-item" class="graphictoria-smaller-page"
@auth
data-asset-id="{{ $asset->id }}"
data-asset-name="{{ $asset->name }}"

View File

@ -5,6 +5,125 @@
@section('page-specific')
@endsection
@section('quick-admin')
<li class="nav-item">
{{-- TODO: XlXi: Make this use route() --}}
<a href="{{ url('/admin') }}" class="nav-link py-0">User Admin</a>
</li>
<li class="nav-item">
{{-- TODO: XlXi: Make this use route() --}}
<a href="{{ url('/admin') }}" class="nav-link py-0">Moderate User</a>
</li>
@endsection
@section('content')
<h1>this is {{ $user->username }}'s profile</h1>
<style>
.graphictoria-user-profile-buttons {
display: flex;
justify-content: center;
}
.graphictoria-user-profile-buttons > .btn:not(:last-child) {
/* me-1 */
margin-right: 0.25rem!important;
}
</style>
<div class="container-lg my-2">
<div class="graphictoria-smaller-page">
<div class="row">
<div class="col-md-6">
<div class="card p-2 text-center">
<h5 class="mb-0"><span class="{{ $user->getOnlineClass() }}"></span> {{ $user->username }}</h5>
@if(false)
{{-- TODO: XlXi: this lol --}}
<p class="text-success">[ Playing: Among Us ]</p>
@endif
<img src="{{ asset('/images/testing/avatar.png') }}" width="300px" height="300px" class="img-fluid mx-auto gt-charimg" />
<p class="text-muted pb-2">TODO: user description</p>
@auth
<div class="graphictoria-user-profile-buttons">
<button class="btn btn-secondary">Add Friend</button>
<button class="btn btn-secondary">Send Message</button>
<button class="btn btn-secondary">Block</button>
</div>
@endauth
<hr class="mb-1" />
<div class="row text-center">
<div class="col-4">
<p class="fw-bold">Joined</p>
<p>{{ $user->getJoinDate() }}</p>
</div>
<div class="col-4">
<p class="fw-bold">Last Seen</p>
<p>{{ $user->getLastSeen() }}</p>
</div>
<div class="col-4">
<p class="fw-bold">Visits</p>
<p>0</p>
</div>
</div>
<hr class="mt-1 mb-1" />
@auth
<a href="https://www.gtoria.local/todo123" class="ms-auto text-decoration-none link-danger">Report <i class="fa-solid fa-circle-exclamation"></i></a>
@endauth
</div>
<x-MiniCard class="mt-3 d-flex">
<x-slot name="title">
Official Badges
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
<x-MiniCard class="mt-3 d-flex">
<x-slot name="title">
Badges
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
</div>
<div class="col-md-6">
<x-MiniCard class="mt-3 mt-md-0 d-flex">
<x-slot name="title">
Games
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
<x-MiniCard class="mt-3 d-flex">
<x-slot name="title">
Favorites
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
<x-MiniCard class="mt-3 d-flex">
<x-slot name="title">
Friends
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
</div>
</div>
<x-MiniCard class="mt-3 d-flex">
<x-slot name="title">
Groups
</x-slot>
<x-slot name="body">
<p class="text-muted">todo</p>
</x-slot>
</x-MiniCard>
</div>
</div>
@endsection

View File

@ -2,6 +2,10 @@
Route::get('/', 'ApiController@index')->name('index');
Route::get('/ping', function() {
return response('');
})->middleware('lastseen');
Route::middleware('auth')->group(function () {
Route::group(['as' => 'feed.', 'prefix' => 'feed'], function() {
Route::group(['as' => 'v1.', 'prefix' => 'v1'], function() {

5
web/routes/blog.php Normal file
View File

@ -0,0 +1,5 @@
<?php
Route::get('/', function(){
return view('layouts.blog');
});

View File

@ -17,6 +17,11 @@ Route::group(['as' => 'shop.', 'prefix' => 'shop'], function() {
Route::get('/{asset}/{assetName:slug?}', 'ShopController@showAsset')->name('asset');
});
Route::group(['as' => 'games.', 'prefix' => 'games'], function() {
Route::get('/', 'GamesController@index')->name('index');
//Route::get('/{asset}/{assetName:slug?}', 'GamesController@showGame')->name('game');
});
Route::middleware('auth')->group(function () {
Route::group(['as' => 'user.', 'prefix' => 'my'], function() {
Route::get('/settings', 'SettingsController@index')->name('index');
@ -34,6 +39,8 @@ Route::group(['as' => 'admin.', 'prefix' => 'admin'], function() {
Route::middleware('roleset:owner')->group(function () {
Route::get('/arbiter-management/{arbiterType?}/{jobId?}', 'AdminController@arbiterManagement')->name('arbitermanagement');
Route::get('/configuration', 'AdminController@configuration')->name('configuration');
});
});

View File

@ -69,7 +69,7 @@
<category name="Service">
<link name="Arbiter Management" route="admin.arbitermanagement" />
<link name="Arbiter Diag" route="admin.diag" />
<link name="Configuration Editor" route="admin.dashboard" />
<link name="Configuration Editor" route="admin.configuration" />
<link name="Banner Editor" route="admin.dashboard" />
</category>

View File

@ -11,6 +11,7 @@ mix.js('resources/js/app.js', 'public/js')
.js('resources/js/pages/Dashboard.js', 'public/js')
.js('resources/js/pages/Shop.js', 'public/js')
.js('resources/js/pages/Item.js', 'public/js')
.js('resources/js/pages/SiteConfiguration.js', 'public/js/adm')
.react()
.sass('resources/sass/Graphictoria.scss', 'public/css')
.banner({