Rework user page, more page concepts.

- Added page concept for games.

- User page now mostly resembles what Roblox's user profile page looked like back in 2016.

- Added biography for users.
This commit is contained in:
Graphictoria 2022-10-19 23:57:39 -04:00
parent 550fafeee5
commit 6c482f5a22
12 changed files with 315 additions and 141 deletions

BIN
etc/art/gamebusy.pdn Normal file

Binary file not shown.

View File

@ -91,15 +91,12 @@ class User extends Authenticatable implements MustVerifyEmail
return $this->created_at->isoFormat('ll'); return $this->created_at->isoFormat('ll');
} }
// XlXi: Returns a class name like text-success or // XlXi: TODO: Replace this with detailed presence
// gt-status-studio to show next to the // like what game the user is in or
// user's name. // what place they're editing.
public function getOnlineClass() public function isOnline()
{ {
if($this->last_seen >= Carbon::now()->subMinutes(2)) return ($this->last_seen >= Carbon::now()->subMinutes(2));
return 'text-success';
return 'text-muted';
} }
public function _hasRolesetInternal($roleName) public function _hasRolesetInternal($roleName)

View File

@ -22,6 +22,8 @@ return new class extends Migration
$table->rememberToken(); $table->rememberToken();
$table->unsignedBigInteger('banId')->nullable(); $table->unsignedBigInteger('banId')->nullable();
$table->string('biography')->nullable();
$table->unsignedBigInteger('tokens')->default(0); $table->unsignedBigInteger('tokens')->default(0);
$table->dateTime('next_reward')->useCurrent(); $table->dateTime('next_reward')->useCurrent();

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,120 @@
/*
Graphictoria 5 (https://gtoria.net)
Copyright © XlXi 2022
*/
import { Component, createRef } from 'react';
import classNames from 'classnames/bind';
import axios from 'axios';
import Twemoji from 'react-twemoji';
import { buildGenericApiUrl } from '../util/HTTP.js';
import ProgressiveImage from './ProgressiveImage';
import Loader from './Loader';
axios.defaults.withCredentials = true;
function commaSeparate(num) {
let str = num.toString().split('.');
str[0] = str[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return str.join('.');
}
class GameItemCard extends Component {
constructor(props) {
super(props);
this.state = {
hovered: false
}
}
render() {
return (
<a
className="graphictoria-item-card"
href="#"
onMouseEnter={() => this.setState({hovered: true})}
onMouseLeave={() => this.setState({hovered: false})}
>
<span className="card m-2">
<ProgressiveImage
src={ buildGenericApiUrl('www', 'images/busy/game.png') }
placeholderImg={ buildGenericApiUrl('www', 'images/busy/game.png') }
alt="Game todo"
className='img-fluid'
/>
<div className="p-2">
<p>Todo</p>
<p className="text-muted small">{commaSeparate(1337)} Playing</p>
<div className="d-flex mt-1">
<i className={classNames({
'fa-solid': true,
'fa-thumbs-up': true,
'text-success': this.state.hovered
})}></i>
<div className={classNames({
'my-auto': true,
'mx-1': true,
'graphictoria-vote-bar': true,
'rounded-1': true,
'border': true,
'border-light': true,
'position-relative': true,
'flex-fill': true,
'bg-secondary': !this.state.hovered,
'bg-danger': this.state.hovered
})}>
<div className={classNames({
'rounded-1': true,
'position-absolute': true,
'bg-dark': !this.state.hovered,
'bg-success': this.state.hovered,
})}
style={{width: '80%', height: '8px'}}></div>
</div>
<i className={classNames({
'fa-solid': true,
'fa-thumbs-down': true,
'text-danger': this.state.hovered
})}></i>
</div>
</div>
</span>
{
this.state.hovered ?
<span className="graphictoria-item-details">
<div className="card px-2">
<hr className="m-0" />
<p className="text-truncate my-1">
<span className="text-muted">By </span><a href="#" className="text-decoration-none fw-normal">Todo</a>
</p>
</div>
</span>
:
null
}
</a>
);
}
}
class Games extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="container-lg my-2 d-flex flex-column">
<h4 className="my-auto">Games</h4>
<Loader />
<GameItemCard />
</div>
);
}
}
export default Games;

View File

@ -0,0 +1,19 @@
/*
Graphictoria 5 (https://gtoria.net)
Copyright © XlXi 2022
*/
import $ from 'jquery';
import React from 'react';
import { render } from 'react-dom';
import Games from '../components/Games';
const gamesId = 'gt-games-main';
$(document).ready(function() {
if (document.getElementById(gamesId)) {
render(<Games />, document.getElementById(gamesId));
}
});

View File

@ -1345,3 +1345,29 @@ p {
-webkit-animation-fill-mode: both; -webkit-animation-fill-mode: both;
-webkit-animation-name: dropdownEase; -webkit-animation-name: dropdownEase;
} }
// Voting
.graphictoria-vote-bar {
// border
html.gtoria-dark & {
border-color: $gray-700;
}
html.gtoria-light & {
border-color: $border-color;
}
// rounded-1
border-radius: 0.2rem;
// bg-secondary
background-color: $secondary;
// my-auto and mx-1
margin: auto 0.25rem auto 0.25rem;
// flex-fill
flex: 1 1 auto;
position: relative;
height: 10px;
}

View File

@ -2,6 +2,10 @@
@section('title', 'Games') @section('title', 'Games')
@section('page-specific')
<script src="{{ mix('js/Games.js') }}"></script>
@endsection
@section('content') @section('content')
<div id="gt-games-main" class="container-lg my-2 d-flex flex-column"> <div id="gt-games-main" class="container-lg my-2 d-flex flex-column">
<h4 class="my-auto">Games</h4> <h4 class="my-auto">Games</h4>

View File

@ -8,39 +8,31 @@
@section('content') @section('content')
<div class="container-lg my-2"> <div class="container-lg my-2">
<h4>Hello, {{ Auth::user()->username }}!</h4>
<div class="row"> <div class="row">
<div class="col-md-3"> <div class="col-md-3">
<h4>Hello, {{ Auth::user()->username }}!</h4>
<div class="card text-center"> <div class="card text-center">
<img src="{{ asset('/images/testing/avatar.png') }}" class="img-fluid gt-charimg" /> <img src="{{ asset('/images/testing/avatar.png') }}" class="img-fluid gt-charimg" />
</div> </div>
<x-MiniCard class="mt-3 d-none d-md-flex"> <h4 class="mt-3">Blog</h4>
<x-slot name="title"> <div class="card p-2">
Blog <ul class="text-center list-unstyled mb-0">
</x-slot> <li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li>
<x-slot name="body"> <li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li>
<ul class="text-center list-unstyled mb-1"> <li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li>
<li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li> </ul>
<li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li> <div class="text-left">
<li class="pb-2"><a href="#" class="text-decoration-none fw-normal"><i class="fa-solid fa-circle-right"></i> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></li> <a href="https://blog.gtoria.net" class="text-decoration-none fw-normal" target="_blank">More <i class="fa-solid fa-caret-right"></i></a>
</ul> </div>
<div class="text-left px-2"> </div>
<a href="https://blog.gtoria.net" class="text-decoration-none fw-normal" target="_blank">More <i class="fa-solid fa-caret-right"></i></a>
</div>
</x-slot>
</x-MiniCard>
</div> </div>
<div class="col-md-9 mt-3 mt-md-0"> <div class="col-md-9">
<x-MiniCard class="d-none d-md-flex mb-3"> <h4 class="mt-3 mt-md-0">Recently Played</h4>
<x-slot name="title"> <div class="card p-2 mb-3">
Recently Played Content here.
</x-slot> </div>
<x-slot name="body">
Content here.
</x-slot>
</x-MiniCard>
<div id="gt-dash-feed"></div> <div id="gt-dash-feed"></div>
</div> </div>

View File

@ -1,10 +1,11 @@
{{-- XlXi: References lol --}}
{{-- XlXi: https://cubash.com/@Icseon --}}
{{-- XlXi: https://youtu.be/nouY1ugddcI?t=583 --}}
@extends('layouts.app') @extends('layouts.app')
@section('title', $title) @section('title', $title)
@section('page-specific')
@endsection
@section('quick-admin') @section('quick-admin')
<li class="nav-item"> <li class="nav-item">
{{-- TODO: XlXi: Make this use route() --}} {{-- TODO: XlXi: Make this use route() --}}
@ -17,113 +18,100 @@
@endsection @endsection
@section('content') @section('content')
<style> <div class="container-lg my-4 graphictoria-smaller-page">
.graphictoria-user-profile-buttons { {{-- User pane --}}
display: flex; <div class="card p-2">
justify-content: center; <div class="d-flex">
} <div class="pe-3">
<img class="img-fluid border graphictora-user-circle m-1" src="{{ asset('/images/testing/headshot.png') }}" alt="User avatar of {{ $user->username }}" width="120px" />
.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>
<div class="col-md-6"> <div class="flex-fill d-flex flex-column p-2">
<x-MiniCard class="mt-3 mt-md-0 d-flex"> {{-- TODO: XlXi: Advanced presence --}}
<x-slot name="title"> <h4 class="mb-0">
Games {{ $user->username }}
</x-slot> <span @class([
<x-slot name="body"> 'text-muted' => !$user->isOnline(),
<p class="text-muted">todo</p> 'text-success' => $user->isOnline()
</x-slot> ])>({{ $user->isOnline() ? 'Online' : 'Offline' }})</span>
</x-MiniCard> </h4>
<p>"This is my current status!"</p>
<x-MiniCard class="mt-3 d-flex"> <div class="d-md-flex mt-auto">
<x-slot name="title"> <a href="#" class="btn btn-primary ms-auto">Send Message</a>
Favorites <a href="#" class="btn btn-success ms-1">Add Friend</a>
</x-slot> </div>
<x-slot name="body"> </div>
<p class="text-muted">todo</p> </div>
</x-slot> </div>
</x-MiniCard>
{{-- About pane --}}
<x-MiniCard class="mt-3 d-flex"> <h4 class="mt-2">About</h4>
<x-slot name="title"> <div class="card p-2">
Friends @if($user->biography)
</x-slot> <p>{{ $user->biography }}</p>
<x-slot name="body"> @else
<p class="text-muted">todo</p> <i class="text-muted">This user has no description.</i>
</x-slot> @endif
</x-MiniCard> <hr class="my-2" />
<div class="d-flex">
{{-- TODO: XlXi: convert this to a route --}}
<a href="https://www.gtoria.local/report/user/notfinishedtodo" target="_blank" class="text-decoration-none link-danger ms-auto">Report <i class="fa-solid fa-circle-exclamation"></i></a>
</div>
</div>
{{-- Games pane --}}
<h4 class="mt-2">Games</h4>
<div class="card p-3">
<div>
{{-- XlXi: just reuse the shop cards for this lol --}}
{{-- XlXi: https://cdn.discordapp.com/attachments/845538783592054795/1028135570335092826/unknown.png --}}
</div>
</div>
<div class="row">
<div class="col-md-6">
{{-- Badges pane --}}
<h4 class="mt-2">Badges</h4>
<div class="card p-2">
{{-- TODO: XlXi: badges --}}
</div>
</div>
<div class="col-md-6">
{{-- Friends pane --}}
<h4 class="mt-2">Friends</h4>
<div class="card p-2">
{{-- TODO: XlXi: friends --}}
{{-- TODO: XlXi: Sort friends by online --}}
</div>
</div>
</div>
{{-- Groups pane --}}
<h4 class="mt-2">Groups</h4>
<div class="card p-2">
</div>
{{-- Statistics pane --}}
<h4 class="mt-2">Statistics</h4>
<div class="card p-3">
<div class="row text-center">
<div class="col">
<p class="fw-bold">Joined</p>
<p>{{ $user->getJoinDate() }}</p>
</div>
<div class="col">
<p class="fw-bold">Last Seen</p>
<p>{{ $user->getLastSeen() }}</p>
</div>
<div class="col">
<p class="fw-bold">Visits</p>
<p>todo</p>
</div>
<div class="col">
<p class="fw-bold">Forum Posts</p>
<p>todo</p>
</div> </div>
</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>
</div> </div>
@endsection @endsection

View File

@ -8,6 +8,31 @@
@section('content') @section('content')
<div id="gt-settings-main" class="container mx-auto my-2"> <div id="gt-settings-main" class="container mx-auto my-2">
<h4 class="my-auto">Settings</h4> <h4 class="my-auto">Settings</h4>
<x-loader />
<ul class="nav nav-tabs">
<li class="nav-item">
<button class="nav-link active">Account</button>
</li>
<li class="nav-item">
<button class="nav-link">Security</button>
</li>
<li class="nav-item">
<button class="nav-link">Privacy</button>
</li>
<li class="nav-item">
<button class="nav-link">Appearance</button>
</li>
</ul>
<div class="card p-2">
<h5>Account Settings</h5>
<div class="row">
<div class="col-3 fw-bold">
<p>Username</p>
</div>
<div class="col-9">
<p>XlXi</p>
</div>
</div>
</div>
</div> </div>
@endsection @endsection

View File

@ -11,6 +11,7 @@ mix.js('resources/js/app.js', 'public/js')
.js('resources/js/pages/Maintenance.js', 'public/js') .js('resources/js/pages/Maintenance.js', 'public/js')
.js('resources/js/pages/Dashboard.js', 'public/js') .js('resources/js/pages/Dashboard.js', 'public/js')
.js('resources/js/pages/Shop.js', 'public/js') .js('resources/js/pages/Shop.js', 'public/js')
.js('resources/js/pages/Games.js', 'public/js')
.js('resources/js/pages/Item.js', 'public/js') .js('resources/js/pages/Item.js', 'public/js')
.js('resources/js/pages/SiteConfiguration.js', 'public/js/adm') .js('resources/js/pages/SiteConfiguration.js', 'public/js/adm')
.react() .react()