Initial commit

This commit is contained in:
Daniel Brendel 2022-08-16 13:54:30 +02:00
commit 94353ac3c8
64 changed files with 32771 additions and 0 deletions

46
.env.example Normal file
View File

@ -0,0 +1,46 @@
# Asatru PHP - App environment configuration file
#
# Scheme:
# name=value
# Example
# APP_NAME="My App name"
# Datatypes:
# string, integer, float, boolean and null (auto detected)
# App settings
APP_NAME="SteamCards"
APP_VERSION=1.0
APP_AUTHOR="Daniel Brendel"
APP_CONTACT="dbrendel1988@gmail.com"
APP_TITLE="${APP_NAME} - Integrate Steam Cards into your website"
APP_DESCRIPTION="Integrate Steam Cards of your game/app into your website"
APP_KEYWORDS="steam, cards, steam cards, widgets"
APP_DEBUG=true
APP_BASEDIR=""
APP_SESSION=true
APP_LINK_GITHUB="https://github.com/danielbrendel"
APP_LINK_TWITTER="https://twitter.com/dbrendel_dev"
APP_LINK_STEAM="https://store.steampowered.com/developer/danielbrendel/"
APP_PACKAGE="danielbrendel/steamcards-web"
APP_SHOWNPMUSAGE=true
APP_NPMPACKAGEURL=""
STEAM_API_KEY=""
# Database settings
DB_ENABLE=false
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=""
DB_PORT=3306
DB_DATABASE=asatru
DB_DRIVER=mysql
# SMTP settings
SMTP_FROMNAME="Test"
SMTP_FROMADDRESS="test@domain.tld"
SMTP_HOST=""
SMTP_PORT=587
SMTP_USERNAME=""
SMTP_PASSWORD=""
SMTP_ENCRYPTION=tls

35
.env.testing Normal file
View File

@ -0,0 +1,35 @@
# Asatru PHP - App environment configuration file
#
# Scheme:
# name=value
# Example
# APP_NAME="My App name"
# Datatypes:
# string, integer, float, boolean and null (auto detected)
# App settings
APP_NAME="Asatru PHP"
APP_VERSION=1.0
APP_AUTHOR="Daniel Brendel"
APP_CONTACT="dbrendel1988@gmail.com"
APP_DEBUG=true
APP_BASEDIR=""
APP_SESSION=true
# Database settings
DB_ENABLE=true
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=""
DB_PORT=3306
DB_DATABASE=asatru
DB_DRIVER=mysql
# SMTP settings
SMTP_FROMNAME="Test"
SMTP_FROMADDRESS="test@domain.tld"
SMTP_HOST=""
SMTP_PORT=587
SMTP_USERNAME=""
SMTP_PASSWORD=""
SMTP_ENCRYPTION=tls

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/app/logs
/vendor
/node_modules
.env
.phpunit.result.cache

6
.htaccess Normal file
View File

@ -0,0 +1,6 @@
RewriteEngine On
RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]
RewriteRule ^((?!public/).*)$ public/$1 [L,NC]

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2022 Daniel Brendel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# SteamCards Web Project
(C) 2022 by Daniel Brendel
__Contact__: dbrendel1988(at)gmail(dot)com\
__GitHub__: https://github.com/danielbrendel
Released under the MIT license
## Description
This is the web backend as well as the documentation and resource provider for SteamCards.
SteamCards offers the possibility to comfortably render Steam related cards into your web
document with as less effort as possible.
## Current featured cards
- Steam App Widget: Renders a card of a Steam app/game
- Steam Server Widget: Renders a card of a Steam game server
- Steam User Widget: Renders a card of a Steam user

19
app/config/autoload.php Normal file
View File

@ -0,0 +1,19 @@
<?php
/*
Asatru PHP - autoload configuration file
Add here all files you want to be autoloaded
Schema:
<path>
Example:
/helper/myscript.php
Explanation:
Will autoload /helper/myscript.php relative
to the /app directory
*/
return [
'/helper/TestHelper.php'
];

18
app/config/events.php Normal file
View File

@ -0,0 +1,18 @@
<?php
/*
Asatru PHP - events configuration file
Add here all your event handlers
Schema:
<event name> = <event class>@<event handler>
Example:
'my_event' => 'EventHandler@myEvent'
Explanation:
Will register the event handler with the event
*/
return [
'my_event' => 'EventHandler@myEvent'
];

26
app/config/routes.php Normal file
View File

@ -0,0 +1,26 @@
<?php
/*
Asatru PHP - routes configuration file
Add here all your needed routes.
Schema:
[<url>, <method>, controller_file@controller_method]
Example:
[/my/route, get, mycontroller@index]
[/my/route/with/{param1}/and/{param2}, get, mycontroller@another]
Explanation:
Will call index() in app\controller\mycontroller.php if request is 'get'
Every route with $ prefix is a special route
*/
return [
array('/', 'GET', 'index@index'),
array('/generator', 'GET', 'index@generator'),
array('/api/query/app', 'GET', 'api@queryAppInfo'),
array('/api/query/server', 'GET', 'api@queryServerInfo'),
array('/api/query/user', 'GET', 'api@queryUserInfo'),
array('/api/resource/query', 'GET', 'api@queryResource'),
array('$404', 'ANY', 'error404@index')
];

38
app/controller/_base.php Normal file
View File

@ -0,0 +1,38 @@
<?php
/**
* Base controller class
*
* Extend or modify to fit your project needs
*/
class BaseController extends Asatru\Controller\Controller {
/**
* @var string
*/
protected $layout = 'layout';
/**
* Perform base initialization
*
* @param $layout
* @return void
*/
public function __construct($layout = '')
{
if ($layout !== '') {
$this->layout = $layout;
}
}
/**
* A more convenient view helper
*
* @param array $yields
* @param array $attr
* @return Asatru\View\ViewHandler
*/
public function view($yields, $attr = array())
{
return view($this->layout, $yields, $attr);
}
}

103
app/controller/api.php Normal file
View File

@ -0,0 +1,103 @@
<?php
/**
* API controller
*/
class ApiController extends BaseController {
/**
* Construct object
*
* @return void
*/
public function __construct()
{
header('Access-Control-Allow-Origin: *');
}
/**
* Query Steam game/app data
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\JsonHandler
*/
public function queryAppInfo($request)
{
try {
$appid = $request->params()->query('appid', null);
$language = $request->params()->query('lang', 'english');
$data = SteamApp::querySteamData($appid, $language);
return json(array('code' => 200, 'appid' => $appid, 'lang' => $language, 'data' => $data));
} catch (\Exception $e) {
return json(array('code' => 500, 'msg' => $e->getMessage()));
}
}
/**
* Query Steam server data
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\JsonHandler
*/
public function queryServerInfo($request)
{
try {
$addr = $request->params()->query('addr', null);
$data = SteamServer::querySteamData(env('STEAM_API_KEY'), $addr);
return json(array('code' => 200, 'addr' => $addr, 'data' => $data));
} catch (\Exception $e) {
return json(array('code' => 500, 'msg' => $e->getMessage()));
}
}
/**
* Query Steam user data
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\JsonHandler
*/
public function queryUserInfo($request)
{
try {
$steamid = $request->params()->query('steamid', null);
$data = SteamUser::querySteamData(env('STEAM_API_KEY'), $steamid);
return json(array('code' => 200, 'steamid' => $steamid, 'data' => $data));
} catch (\Exception $e) {
return json(array('code' => 500, 'msg' => $e->getMessage()));
}
}
/**
* Query JavaScript or CSS resource for component
*
* @param Asatru\Controller\ControllerArg $request
* @return mixed
*/
public function queryResource($request)
{
$res = $request->params()->query('type');
$module = $request->params()->query('module');
$ver = $request->params()->query('version', 'v1');
if ($res === 'js') {
if (file_exists(public_path('/js/steamcards/' . $ver . '/steam_' . $module . '.js'))) {
return redirect(asset('js/steamcards/' . $ver . '/steam_' . $module . '.js'));
} else {
http_response_code(404);
exit();
}
} else if ($res === 'css') {
if (file_exists(public_path('/css/steamcards/' . $ver . '/steam_' . $module . '.css'))) {
return redirect(asset('css/steamcards/' . $ver . '/steam_' . $module . '.css'));
} else {
http_response_code(404);
exit();
}
}
}
}

View File

@ -0,0 +1,25 @@
<?php
/**
* Example error 404 controller
*/
class Error404Controller extends BaseController {
/**
* Handles special case: $404
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\ViewHandler
*/
public function index($request)
{
//Add a log line
addLog(ASATRU_LOG_INFO, "Error 404");
//Generate the 404 view
$v = new Asatru\View\ViewHandler();
$v->setLayout('layout') //The layout file. Will be \app\views\layout.php
->setYield('yield', 'error/404'); //The index yield. Will be \app\views\error\404.php
return $v; //Pass the object to the engine
}
}

42
app/controller/index.php Normal file
View File

@ -0,0 +1,42 @@
<?php
/**
* Index controller
*/
class IndexController extends BaseController {
const INDEX_LAYOUT = 'layout';
/**
* Perform base initialization
*
* @return void
*/
public function __construct()
{
parent::__construct(self::INDEX_LAYOUT);
}
/**
* Handles URL: /
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\ViewHandler
*/
public function index($request)
{
//Generate and return a view by using the helper
return parent::view(['content', 'index']);
}
/**
* Handles URL: /generator
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\ViewHandler
*/
public function generator($request)
{
//Generate and return a view by using the helper
return view('generator', []);
}
}

View File

@ -0,0 +1,20 @@
<?php
/*
Asatru PHP - Example event handler
*/
/**
* Example event handler class
*/
class EventHandler {
/**
* Example event handler method
*
* @param $data optional
* @return void
*/
public function myEvent($data = null)
{
}
}

16
app/helper/TestHelper.php Normal file
View File

@ -0,0 +1,16 @@
<?php
/*
Asatru PHP - example helper
*/
/**
* Just an example helper function
*
* @param int $max
* @return int
*/
function MyExampleHelperFunction($max = 1000)
{
return rand(1, $max);
}

14
app/lang/en/app.php Normal file
View File

@ -0,0 +1,14 @@
<?php
/*
Asatru PHP - English language file
Extend this with your phrases
Set variables with {variable-name}
*/
return [
'welcome' => 'Welcome to the Asatru PHP framework',
'description' => 'You have successfully installed the Asatru PHP framework. You may now want to start developing your app. Consider the documentation located in /doc for help. Have fun with the framework!'
];

20
app/lang/en/errors.php Normal file
View File

@ -0,0 +1,20 @@
<?php
/*
Asatru PHP - English language file for errors
Modify and add error related messages here
Set variables with {variable-name}
*/
return [
'csrf_token_invalid' => 'CSRF token is missing or invalid',
'item_required' => 'Item {key} is required.',
'item_email' => 'Item {key} must be a valid E-Mail address',
'item_too_short' => 'Item length of {key} must be greater than {min}',
'item_too_large' => 'Item length of {key} must be less than {max}',
'item_datetime' => 'Item {key} is not a valid datetime object',
'item_number' => 'Item {key} is not a valid number',
'item_regex' => 'Item {key} does not fit pattern {pattern}'
];

87
app/modules/SteamApp.php Normal file
View File

@ -0,0 +1,87 @@
<?php
/**
* Class SteamAppModel
*
* Responsible for querying Steam game/app data
*/
class SteamApp
{
const STEAM_ENDPOINT = 'https://store.steampowered.com/api/appdetails';
/**
* Query item data from Steam
*
* @param $appid
* @param $lang
* @return mixed
* @throws \Exception
*/
public static function querySteamData($appid, $lang)
{
$url = self::STEAM_ENDPOINT . "?appids={$appid}&l={$lang}";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($handle);
if(curl_error($handle) !== '') {
throw new \Exception('cURL error occured');
}
curl_close($handle);
$obj = json_decode($response);
if ((isset($obj->$appid->success)) && ($obj->$appid->success)) {
$obj->$appid->data->online_count = 0;
try {
$obj->$appid->data->online_count = static::queryUserCount($appid);
} catch (\Exception $e) {
}
return $obj->$appid->data;
}
throw new \Exception('Invalid data response');
}
/**
* Query Steam product player/user count
*
* @param $appid
* @return mixed
* @throws \Exception
*/
public static function queryUserCount($appid)
{
$url = "https://api.steampowered.com/ISteamUserStats/GetNumberOfCurrentPlayers/v1/?appid={$appid}";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($handle);
if(curl_error($handle) !== '') {
throw new \Exception('cURL error occured');
}
curl_close($handle);
$obj = json_decode($response);
if ((isset($obj->response->result)) && ($obj->response->result)) {
return $obj->response->player_count;
}
throw new \Exception('Invalid data response');
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Class SteamServerModel
*
* Responsible for querying Steam server data
*/
class SteamServer
{
const STEAM_ENDPOINT = 'https://api.steampowered.com/IGameServersService/GetServerList/v1/';
/**
* Query item data from Steam
*
* @param $appid
* @param $lang
* @return mixed
* @throws \Exception
*/
public static function querySteamData($key, $addr)
{
$url = self::STEAM_ENDPOINT . "?key={$key}&filter=addr\\{$addr}";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($handle);
if(curl_error($handle) !== '') {
throw new \Exception('cURL error occured');
}
curl_close($handle);
$obj = json_decode($response);
if (isset($obj->response->servers[0])) {
return $obj->response->servers[0];
}
throw new \Exception('Invalid data response');
}
}

46
app/modules/SteamUser.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Class SteamUserModel
*
* Responsible for querying Steam user data
*/
class SteamUser
{
const STEAM_ENDPOINT = 'https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/';
/**
* Query item data from Steam
*
* @param $appid
* @param $lang
* @return mixed
* @throws \Exception
*/
public static function querySteamData($key, $steamid)
{
$url = self::STEAM_ENDPOINT . "?key={$key}&steamids={$steamid}";
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($handle);
if(curl_error($handle) !== '') {
throw new \Exception('cURL error occured');
}
curl_close($handle);
$obj = json_decode($response);
if (isset($obj->response->players[0])) {
return $obj->response->players[0];
}
throw new \Exception('Invalid data response');
}
}

View File

@ -0,0 +1,89 @@
.steam-app {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-app-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-app-infos {
position: relative;
padding: 15px;
}
.steam-app-title {
width: 100%;
margin-bottom: 10px;
}
.steam-app-title-name {
display: inline-block;
color: rgb(220, 220, 220);
font-size: 1.1em;
font-family: Verdana, Arial, sans-serif;
}
.steam-app-title-count {
position: relative;
display: inline-block;
top: 5px;
color: rgb(55, 230, 111);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
float: right;
}
.steam-app-description {
width: 100%;
color: rgb(150, 150, 150);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
margin-bottom: 20px;
}
.steam-app-footer {
width: 100%;
margin-bottom: 10px;
}
.steam-app-footer-author {
display: inline-block;
color: rgb(200, 200, 200);
font-family: Verdana, Arial, sans-serif;
font-size: 0.8em;
}
.steam-app-footer-button {
display: inline-block;
float: right;
}
.steam-app-footer-button a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-app-footer-button a:hover {
color: rgb(250, 250, 250);
}

View File

@ -0,0 +1,103 @@
.steam-server {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-server-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-server-infos {
position: relative;
padding: 15px;
}
.steam-server-title {
}
.steam-server-title-left {
position: relative;
display: inline-block;
}
.steam-server-title-left-addr {
color: rgb(200, 200, 200);
}
.steam-server-title-left-name {
color: rgb(150, 150, 150);
font-size: 0.8em;
}
.steam-server-title-right {
position: relative;
display: inline-block;
float: right;
}
.steam-server-title-right-count {
color: rgb(130, 130, 130);
font-size: 0.7em;
}
.steam-server-title-right-bots {
color: rgb(130, 130, 130);
font-size: 0.7em;
}
.steam-server-gameinfo {
position: relative;
display: inline-block;
margin-top: 10px;
margin-bottom: 10px;
}
.steam-server-gameinfo-item {
color: rgb(150, 150, 150);
font-size: 0.65em;
}
.steam-server-gameinfo-item-green {
color: rgb(85, 190, 111);
}
.steam-server-gameinfo-item-red {
color: rgb(179, 115, 115);
}
.steam-server-action {
position: relative;
display: inline-block;
float: right;
margin-top: 10px;
margin-bottom: 10px;
}
.steam-server-action a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-server-action a:hover {
color: rgb(250, 250, 250);
}

View File

@ -0,0 +1,97 @@
.steam-user {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-user-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-user-infos {
position: relative;
padding: 15px;
}
.steam-user-infos-left {
position: relative;
display: inline-block;
}
.steam-user-infos-left-avatar {
position: relative;
display: inline-block;
}
.steam-user-infos-left-avatar img {
width: 64px;
height: 64px;
border-radius: 50%;
}
.steam-user-infos-left-text {
position: relative;
display: inline-block;
top: -16px;
margin-left: 10px;
}
.steam-user-infos-left-text-name {
color: rgb(200, 200, 200);
}
.steam-user-infos-left-text-since {
color: rgb(150, 150, 150);
font-size: 0.8em;
}
.steam-user-infos-right {
position: relative;
display: inline-block;
margin-right: 5px;
float: right;
}
.steam-user-infos-right-online {
position: relative;
top: 11px;
color: rgb(100, 100, 100);
font-size: 0.8em;
}
.steam-user-infos-right-online-green {
color: rgb(85, 190, 111);
}
.steam-user-infos-right-view {
position: relative;
top: 15px;
}
.steam-user-infos-right-view a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-user-infos-right-view a:hover {
color: rgb(250, 250, 250);
}

39
app/resources/js/app.js Normal file
View File

@ -0,0 +1,39 @@
/**
* app.js
*
* Put here your application specific JavaScript implementations
*/
window.vue = new Vue({
el: '#app',
data: {
},
methods: {
initNavBar: function() {
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
if ($navbarBurgers.length > 0) {
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
},
}
});
import hljs from 'highlight.js';
import 'highlight.js/scss/github.scss';
window.hljs = hljs;
document.addEventListener('DOMContentLoaded', function(){
window.hljs.highlightAll();
});

View File

@ -0,0 +1,396 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam Game/App Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_APP_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_APP_VERSION = 'v1';
/**
* Class SteamAppElem
*
* Handle custom HTML element to render Steam app/game widgets
*/
class SteamAppElem extends HTMLElement
{
storedData = {};
connectedCallback()
{
var appid = (typeof this.attributes.appid !== 'undefined') ? this.attributes.appid.value : null;
var lang = (typeof this.attributes.lang !== 'undefined') ? this.attributes.lang.value : 'english';
var playtext = (typeof this.attributes.playtext !== 'undefined') ? this.attributes.playtext.value : 'Play on Steam';
var author = (typeof this.attributes.author !== 'undefined') ? this.attributes.author.value : 'By :developer';
var onlinecount = (typeof this.attributes.onlinecount !== 'undefined') ? this.attributes.onlinecount.value : null;
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTitle = (typeof this.attributes['style-color-title'] !== 'undefined') ? this.attributes['style-color-title'].value : null;
var styleColorDescription = (typeof this.attributes['style-color-description'] !== 'undefined') ? this.attributes['style-color-description'].value : null;
var styleColorAuthor = (typeof this.attributes['style-color-author'] !== 'undefined') ? this.attributes['style-color-author'].value : null;
var styleColorOnlinecount = (typeof this.attributes['style-color-onlinecount'] !== 'undefined') ? this.attributes['style-color-onlinecount'].value : null;
var styleHideImage = (typeof this.attributes['style-hideimage'] !== 'undefined') ? parseInt(this.attributes['style-hideimage'].value) : 0;
if (appid !== null) {
this.storedData = {
appid: appid,
lang: lang,
playtext: playtext,
author: author,
onlinecount: onlinecount,
width: width,
height: height,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTitle: styleColorTitle,
styleColorDescription: styleColorDescription,
styleColorAuthor: styleColorAuthor,
styleColorOnlinecount: styleColorOnlinecount,
styleHideImage: styleHideImage
};
this.setupCard(
appid,
lang,
playtext,
author,
onlinecount,
width,
height,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTitle,
styleColorDescription,
styleColorAuthor,
styleColorOnlinecount,
styleHideImage
);
}
}
setupCard(appid, lang, playtext, author, onlinecount, width, height, styleBorder, styleShadow, styleColorBackground, styleColorTitle, styleColorDescription, styleColorAuthor, styleColorOnlinecount, styleHideImage)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (author.indexOf(':developer') !== false) {
let developers = '';
json.data.developers.forEach(function(elem, index) {
developers += elem;
if (index < json.data.developers.length - 1) {
developers += ', ';
}
});
author = author.replace(':developer', developers);
}
if (author.indexOf(':publisher') !== false) {
let publishers = '';
json.data.publishers.forEach(function(elem, index) {
publishers += elem;
if (index < json.data.publishers.length - 1) {
publishers += ', ';
}
});
author = author.replace(':publisher', publishers);
}
if (!document.getElementById('steamcards-app-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-app-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_APP_ENDPOINT + '/api/resource/query?type=css&module=app&version=' + STEAMCARDS_APP_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let onlineCountText = '';
if ((onlinecount !== null) && (json.data.online_count > 0)) {
onlineCountText = onlinecount;
onlineCountText = onlineCountText.replace(':count', self.readableCount(json.data.online_count));
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let html = `
<div class="steam-app" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-app-image" style="background-image: url('` + json.data.header_image + `'); ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + ((styleHideImage) ? 'display: none;' : '') + `"></div>
<div class="steam-app-infos">
<div class="steam-app-title">
<div class="steam-app-title-name" ` + ((styleColorTitle !== null) ? 'style="color: ' + styleColorTitle + ';"' : '') + `>` + json.data.name + `</div>
<div class="steam-app-title-count" ` + ((styleColorOnlinecount !== null) ? 'style="color: ' + styleColorOnlinecount + ';"' : '') + `>` + ((onlineCountText.length > 0) ? onlineCountText : '') + `</div>
</div>
<div class="steam-app-description" ` + ((styleColorDescription !== null) ? 'style="color: ' + styleColorDescription + ';"' : '') + `>
` + json.data.short_description + `
</div>
<div class="steam-app-footer">
<div class="steam-app-footer-author" ` + ((styleColorAuthor !== null) ? 'style="color: ' + styleColorAuthor + ';"' : '') + `>
` + author + `
</div>
<div class="steam-app-footer-button">
<a href="https://store.steampowered.com/app/` + json.appid + `">` + playtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_APP_ENDPOINT + '/api/query/app?appid=' + appid + '&lang=' + lang, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
changeLang(lang, playtext, author, onlinecount)
{
this.storedData.lang = lang;
this.storedData.playtext = playtext;
this.storedData.author = author;
this.storedData.onlinecount = onlinecount;
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
setImageVisibility(visibility)
{
this.storedData.styleHideImage = !visibility;
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
readableCount(count)
{
const COUNT_MILLION = 1000000;
const COUNT_HUNDREDTHOUSAND = 100000;
const COUNT_TENTHOUSAND = 10000;
const COUNT_THOUSAND = 1000;
if (count >= COUNT_MILLION) {
return (Math.round(count / COUNT_MILLION, 1)).toString() + 'M';
} else if ((count < COUNT_MILLION) && (count >= COUNT_HUNDREDTHOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else if ((count < COUNT_HUNDREDTHOUSAND) && (count >= COUNT_TENTHOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else if ((count < COUNT_TENTHOUSAND) && (count >= COUNT_THOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else {
return count.toString();
}
}
}
window.customElements.define('steam-app', SteamAppElem);
/**
* Class SteamApp
*
* Dynamically create a Steam game/app card via JavaScript
*/
class SteamApp
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var appid = (typeof config.appid !== 'undefined') ? config.appid : null;
var lang = (typeof config.lang !== 'undefined') ? config.lang : 'english';
var onlinecount = (typeof config.onlinecount !== 'undefined') ? config.onlinecount : null;
var playtext = (typeof config.playtext !== 'undefined') ? config.playtext : 'Play on Steam';
var author = (typeof config.author !== 'undefined') ? config.author : 'By :developer';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTitle = null;
var styleColorDescription = null;
var styleColorAuthor = null;
var styleColorOnlinecount = null;
var styleHideImage = 0;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTitle = (typeof config.style.colorTitle !== 'undefined') ? config.style.colorTitle : null;
styleColorDescription = (typeof config.style.colorDescription !== 'undefined') ? config.style.colorDescription : null;
styleColorAuthor = (typeof config.style.colorAuthor !== 'undefined') ? config.style.colorAuthor : null;
styleColorOnlinecount = (typeof config.style.colorOnlinecount !== 'undefined') ? config.style.colorOnlinecount : null;
styleHideImage = (typeof config.style.hideimage !== 'undefined') ? config.style.hideimage : 0;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
if (typeof styleHideImage === 'boolean') {
styleHideImage = (styleHideImage) ? 1 : 0;
}
this.elem = document.createElement('steam-app');
this.elem.setAttribute('appid', appid);
this.elem.setAttribute('lang', lang);
this.elem.setAttribute('playtext', playtext);
this.elem.setAttribute('author', author);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-title', styleColorTitle);
this.elem.setAttribute('style-color-description', styleColorDescription);
this.elem.setAttribute('style-color-author', styleColorAuthor);
this.elem.setAttribute('style-color-onlinecount', styleColorOnlinecount);
this.elem.setAttribute('style-hideimage', styleHideImage);
if (onlinecount !== null) {
this.elem.setAttribute('onlinecount', onlinecount);
}
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(lang, playtext, author, onlinecount)
{
this.elem.changeLang(lang, playtext, author, onlinecount);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

View File

@ -0,0 +1,377 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam Server Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_SERVER_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_SERVER_VERSION = 'v1';
/**
* Class SteamServerElem
*
* Handle custom HTML element to render Steam server widgets
*/
class SteamServerElem extends HTMLElement
{
storedData = {};
oldHeader = '';
connectedCallback()
{
var addr = (typeof this.attributes.addr !== 'undefined') ? this.attributes.addr.value : null;
var header = (typeof this.attributes.header !== 'undefined') ? this.attributes.header.value : '';
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var bots = (typeof this.attributes.bots !== 'undefined') ? this.attributes.bots.value : ':count bots';
var secure_yes = (typeof this.attributes['secure-yes'] !== 'undefined') ? this.attributes['secure-yes'].value : 'secure';
var secure_no = (typeof this.attributes['secure-no'] !== 'undefined') ? this.attributes['secure-no'].value : 'insecure';
var hosting_dedicated = (typeof this.attributes['hosting-dedicated'] !== 'undefined') ? this.attributes['hosting-dedicated'].value : 'dedicated';
var hosting_listen = (typeof this.attributes['hosting-listen'] !== 'undefined') ? this.attributes['hosting-listen'].value : 'listen';
var playtext = (typeof this.attributes.playtext !== 'undefined') ? this.attributes.playtext.value : 'Join';
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTextBright = (typeof this.attributes['style-color-text-bright'] !== 'undefined') ? this.attributes['style-color-text-bright'].value : null;
var styleColorTextDark = (typeof this.attributes['style-color-text-dark'] !== 'undefined') ? this.attributes['style-color-text-dark'].value : null;
if (addr !== null) {
this.storedData = {
addr: addr,
header: header,
width: width,
height: height,
bots: bots,
secure_yes: secure_yes,
secure_no: secure_no,
hosting_dedicated: hosting_dedicated,
hosting_listen: hosting_listen,
playtext: playtext,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTextBright,
styleColorTextDark
};
this.setupCard(
addr,
header,
width,
height,
bots,
secure_yes,
secure_no,
hosting_dedicated,
hosting_listen,
playtext,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTextBright,
styleColorTextDark
);
}
}
setupCard(addr, header, width, height, bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext, styleBorder, styleShadow, styleColorBackground, styleColorTextBright, styleColorTextDark)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamcards-server-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-server-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_SERVER_ENDPOINT + '/api/resource/query?type=css&module=server&version=' + STEAMCARDS_SERVER_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let bgimage = '';
if (header !== '') {
bgimage = 'background-image: url(\'' + header + '\');';
}
bots = bots.replace(':count', json.data.bots);
let security = '';
let seccol = '';
if (json.data.secure) {
security = secure_yes;
seccol = 'steam-server-gameinfo-item-green';
} else {
security = secure_no;
seccol = 'steam-server-gameinfo-item-red';
}
let hosting = '';
if (json.data.dedicated) {
hosting = hosting_dedicated;
} else {
hosting = hosting_listen;
}
let html = `
<div class="steam-server" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-server-image" style="` + bgimage + ` ` + ((header == '') ? 'display: none;' : '') + ` ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + `"></div>
<div class="steam-server-infos">
<div class="steam-server-title">
<div class="steam-server-title-left">
<div class="steam-server-title-left-addr" ` + ((styleColorTextBright !== null) ? 'style="color: ' + styleColorTextBright + ';"' : '') + `>` + json.data.addr + `</div>
<div class="steam-server-title-left-name" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>`+ json.data.name + `</div>
</div>
<div class="steam-server-title-right">
<div class="steam-server-title-right-count" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + json.data.players + `/` + json.data.max_players + `</div>
<div class="steam-server-title-right-bots" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + bots + `</div>
</div>
</div>
<div class="steam-server-footer">
<div class="steam-server-gameinfo" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>
<span class="steam-server-gameinfo-item">` + json.data.product + `</span>
|
<span class="steam-server-gameinfo-item">`+ json.data.map + `</span>
|
<span class="steam-server-gameinfo-item ` + seccol + `">` + security + `</span>
|
<span class="steam-server-gameinfo-item">` + hosting + `</span>
</div>
<div class="steam-server-action">
<a href="steam://connect/` + json.data.addr + `">` + playtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_SERVER_ENDPOINT + '/api/query/server?addr=' + addr, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext)
{
this.storedData.bots = bots;
this.storedData.secure_yes = secure_yes;
this.storedData.secure_no = secure_no;
this.storedData.hosting_dedicated = hosting_dedicated;
this.storedData.hosting_listen = hosting_listen;
this.storedData.playtext = playtext;
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
setImageVisibility(visibility)
{
if (visibility) {
this.storedData.header = this.oldHeader;
} else {
if (this.storedData.header != '') {
this.oldHeader = this.storedData.header;
}
this.storedData.header = '';
}
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
}
window.customElements.define('steam-server', SteamServerElem);
/**
* Class SteamServer
*
* Dynamically create a Steam server card via JavaScript
*/
class SteamServer
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var addr = (typeof config.addr !== 'undefined') ? config.addr : null;
var header = (typeof config.header !== 'undefined') ? config.header : '';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var bots = (typeof config.bots !== 'undefined') ? config.bots : ':count bots';
var secure_yes = (typeof config.secure_yes !== 'undefined') ? config.secure_yes : 'secure';
var secure_no = (typeof config.secure_no !== 'undefined') ? config.secure_no : 'insecure';
var hosting_dedicated = (typeof config.hosting_dedicated !== 'undefined') ? config.hosting_dedicated : 'dedicated';
var hosting_listen = (typeof config.hosting_listen !== 'undefined') ? config.hosting_listen : 'listen';
var playtext = (typeof config.playtext !== 'undefined') ? config.playtext : 'Join';
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTextBright = null;
var styleColorTextDark = null;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTextBright = (typeof config.style.colorTextBright !== 'undefined') ? config.style.colorTextBright : null;
styleColorTextDark = (typeof config.style.colorTextDark !== 'undefined') ? config.style.colorTextDark : null;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-server');
this.elem.setAttribute('addr', addr);
this.elem.setAttribute('header', header);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-text-bright', styleColorTextBright);
this.elem.setAttribute('style-color-text-dark', styleColorTextDark);
this.elem.setAttribute('bots', bots);
this.elem.setAttribute('secure-yes', secure_yes);
this.elem.setAttribute('secure-no', secure_no);
this.elem.setAttribute('hosting-dedicated', hosting_dedicated);
this.elem.setAttribute('hosting-listen', hosting_listen);
this.elem.setAttribute('playtext', playtext);
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext)
{
this.elem.changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

View File

@ -0,0 +1,344 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam User Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_USER_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_USER_VERSION = 'v1';
/**
* Class SteamUserElem
*
* Handle custom HTML element to render Steam user widgets
*/
class SteamUserElem extends HTMLElement
{
storedData = {};
oldHeader = '';
connectedCallback()
{
var steamid = (typeof this.attributes.steamid !== 'undefined') ? this.attributes.steamid.value : null;
var header = (typeof this.attributes.header !== 'undefined') ? this.attributes.header.value : '';
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var online_yes = (typeof this.attributes['online-yes'] !== 'undefined') ? this.attributes['online-yes'].value : 'online';
var online_no = (typeof this.attributes['online-no'] !== 'undefined') ? this.attributes['online-no'].value : 'offline';
var member_since = (typeof this.attributes['member-since'] !== 'undefined') ? this.attributes['member-since'].value : 'Member since: :year-:month-:day';
var viewtext = (typeof this.attributes.viewtext !== 'undefined') ? this.attributes.viewtext.value : 'View';
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTextBright = (typeof this.attributes['style-color-text-bright'] !== 'undefined') ? this.attributes['style-color-text-bright'].value : null;
var styleColorTextDark = (typeof this.attributes['style-color-text-dark'] !== 'undefined') ? this.attributes['style-color-text-dark'].value : null;
if (steamid !== null) {
this.storedData = {
steamid: steamid,
header: header,
width: width,
height: height,
online_yes: online_yes,
online_no: online_no,
member_since: member_since,
viewtext: viewtext,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTextBright,
styleColorTextDark
};
this.setupCard(
steamid,
header,
width,
height,
online_yes,
online_no,
member_since,
viewtext,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTextBright,
styleColorTextDark
);
}
}
setupCard(steamid, header, width, height, online_yes, online_no, member_since, viewtext, styleBorder, styleShadow, styleColorBackground, styleColorTextBright, styleColorTextDark)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamcards-user-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-user-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_USER_ENDPOINT + '/api/resource/query?type=css&module=user&version=' + STEAMCARDS_USER_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let bgimage = '';
if (header !== '') {
bgimage = 'background-image: url(\'' + header + '\');';
}
let onstatus = '';
let oncolor = '';
if (json.data.personastate) {
onstatus = online_yes;
oncolor = 'steam-user-infos-right-online-green';
} else {
onstatus = online_no;
oncolor = '';
}
let regdate = new Date(json.data.timecreated * 1000);
member_since = member_since.replace(':year', regdate.getFullYear());
member_since = member_since.replace(':month', regdate.getMonth() + 1);
member_since = member_since.replace(':day', regdate.getDate());
let html = `
<div class="steam-user" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-user-image" style="` + bgimage + ` ` + ((header == '') ? 'display: none;' : '') + ` ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + `"></div>
<div class="steam-user-infos">
<div class="steam-user-infos-left">
<div class="steam-user-infos-left-avatar"><img src="` + json.data.avatarfull + `" alt="Avatar"/></div>
<div class="steam-user-infos-left-text">
<div class="steam-user-infos-left-text-name" ` + ((styleColorTextBright !== null) ? 'style="color: ' + styleColorTextBright + ';"' : '') + `>` + json.data.personaname + `</div>
<div class="steam-user-infos-left-text-since" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + member_since + `</div>
</div>
</div>
<div class="steam-user-infos-right">
<div class="steam-user-infos-right-online ` + ((json.data.personastate) ? oncolor : '') + `" ` + (((styleColorTextDark !== null) && (json.data.personastate)) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + onstatus + `</div>
<div class="steam-user-infos-right-view">
<a href="` + json.data.profileurl + `">` + viewtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_USER_ENDPOINT + '/api/query/user?steamid=' + steamid, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
changeLang(online_yes, online_no, member_since, viewtext)
{
this.storedData.online_yes = online_yes;
this.storedData.online_no = online_no;
this.storedData.member_since = member_since;
this.storedData.viewtext = viewtext;
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
setImageVisibility(visibility)
{
if (visibility) {
this.storedData.header = this.oldHeader;
} else {
if (this.storedData.header != '') {
this.oldHeader = this.storedData.header;
}
this.storedData.header = '';
}
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
}
window.customElements.define('steam-user', SteamUserElem);
/**
* Class SteamUser
*
* Dynamically create a Steam user card via JavaScript
*/
class SteamUser
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var steamid = (typeof config.steamid !== 'undefined') ? config.steamid : null;
var header = (typeof config.header !== 'undefined') ? config.header : '';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var online_yes = (typeof config.online_yes !== 'undefined') ? config.online_yes : 'online';
var online_no = (typeof config.online_no !== 'undefined') ? config.online_no : 'offline';
var member_since = (typeof config.member_since !== 'undefined') ? config.member_since : 'Member since: :year-:month-:day';
var viewtext = (typeof config.viewtext !== 'undefined') ? config.viewtext : 'View';
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTextBright = null;
var styleColorTextDark = null;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTextBright = (typeof config.style.colorTextBright !== 'undefined') ? config.style.colorTextBright : null;
styleColorTextDark = (typeof config.style.colorTextDark !== 'undefined') ? config.style.colorTextDark : null;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-user');
this.elem.setAttribute('steamid', steamid);
this.elem.setAttribute('header', header);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-text-bright', styleColorTextBright);
this.elem.setAttribute('style-color-text-dark', styleColorTextDark);
this.elem.setAttribute('online-yes', online_yes);
this.elem.setAttribute('online-no', online_no);
this.elem.setAttribute('member-since', member_since);
this.elem.setAttribute('viewtext', viewtext);
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(online_yes, online_no, member_since, viewtext)
{
this.elem.changeLang(online_yes, online_no, member_since, viewtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

156
app/resources/sass/app.scss Normal file
View File

@ -0,0 +1,156 @@
/*
app.scss
*/
html, body {
width: 100%;
height: auto;
margin: 0 auto;
}
body {
overflow-x: hidden;
}
.navbar-start {
@media screen and (min-width: 1088px) {
flex-grow: 1;
justify-content: center;
transform: translate(11%, -0%)
}
}
.is-font-title {
font-family: 'Helvetica', Verdana, Arial, sans-serif;
font-size: 20px;
}
.content-section {
padding: 20px;
}
.content-centered {
text-align: center;
}
.content-top-margin {
margin-top: 90px;
@media screen and (max-width: 1088px) {
margin-top: 58px;
}
}
.content-section h1 {
font-size: 2.0em;
margin-bottom: 10px;
}
.content-section h2 {
font-size: 1.5em;
color: rgb(100, 100, 100);
}
.content-section h3 {
font-size: 1.2em;
color: rgb(100, 100, 100);
margin-bottom: 30px;
}
.content-section p {
margin-bottom: 20px;
}
.content-section a {
color: #3273dc;
}
.content-section a:hover {
color: #3273dc;
text-decoration: underline;
}
.content-section pre {
padding: unset;
margin-top: -15px;
margin-bottom: -61px;
background-color: unset;
}
.content-section code {
background-color: rgb(230, 230, 230);
border-radius: 4px;
}
.content-section ul {
list-style: square;
}
.content-section li {
margin-left: 15px;
}
.content-section table {
margin-bottom: 40px;
}
.content-section tbody {
border: 1px solid #ccc;
}
.content-section td {
padding: 15px;
}
.tr-colored {
background-color: rgb(200, 200, 200);
}
.content-section hr {
background-color: rgb(200, 200, 200);
}
.scroll-to-top {
position: fixed;
z-index: 3;
bottom: 12px;
right: 12px;
}
.scroll-to-top-inner {
background-color: rgb(100, 100, 100);
border-radius: 50%;
padding: 12px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.scroll-to-top-inner a {
color: rgb(200, 200, 200);
}
.scroll-to-top-inner a:hover {
color: rgb(200, 200, 200);
}
.footer {
width: 100%;
color: rgb(100, 100, 100);
background-color: rgb(235, 235, 235);
padding: 1rem 1.5rem 1rem;
}
.footer-frame {
width: 100%;
}
.footer-content {
text-align: center;
}
.footer-content a {
color: rgb(130, 130, 130);
}
.footer-content a:hover {
color: rgb(150, 150, 150);
text-decoration: none;
}

87
app/tests/bootstrap.php Normal file
View File

@ -0,0 +1,87 @@
<?php
/*
Asatru PHP (dnyAsatruPHP) developed by Daniel Brendel
(C) 2019 - 2022 by Daniel Brendel
Version: 1.0
Contact: dbrendel1988<at>gmail<dot>com
GitHub: https://github.com/danielbrendel/
Released under the MIT license
*/
//Set application root directory path
define('ASATRU_APP_ROOT', __DIR__ . '/../..');
//If composer is installed we utilize its autoloader
if (file_exists(__DIR__ . '/../../vendor/autoload.php')) {
require_once __DIR__ . '/../../vendor/autoload.php';
}
//Fetch constants
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/constants.php';
//Require the controller component
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/controller.php';
//Require logging
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/logger.php';
//Require .env config management
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/dotenv.php';
//Require autoload component
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/autoload.php';
//Require helpers
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/helper.php';
//Require mail wrapper
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/mailwrapper.php';
//Require testing component
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/testing.php';
//Parse .env file if it exists
if (file_exists(__DIR__ . '/../../.env.testing')) {
env_parse(__DIR__ . '/../../.env.testing');
}
//Enable debug mode error handling
$_ENV['APP_DEBUG'] = true;
error_reporting(E_ALL);
//Check if we shall create/continue a session
if ((isset($_ENV['APP_SESSION'])) && ($_ENV['APP_SESSION'])) {
if (!session_start()) {
throw new Exception('Failed to create/continue the session');
}
if (!isset($_SESSION['continued'])) { //Check if a new session
//Create CSRF-token
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
//Mark session
$_SESSION['continued'] = true;
}
}
//Require localization
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/locale.php';
//Require database management
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/database.php';
//Require event manager
require_once __DIR__ . '/../../vendor/danielbrendel/asatru-php-framework/src/events.php';
//Perform autoloading
$auto = new Asatru\Autoload\Autoloader(__DIR__ . '/../config/autoload.php');
$auto->load();
//Load validators if any
Asatru\Controller\CustomPostValidators::load(__DIR__ . '/../validators');

46
app/validators/Test.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Test Validator class
*/
class TestValidator extends Asatru\Controller\BaseValidator {
private $error = '';
/**
* Shall return the name of this validator
*
* @return string The identifier of the validator
*/
public function getIdent()
{
return 'testvalidator';
}
/**
* Shall validate a token
*
* @param mixed $value The value of the item to be verified
* @param string $args optional The validator arguments if any
* @return boolean True if the item is valid, otherwise false
*/
public function verify($value, $args = null)
{
if ($value !== $args) {
$this->error = 'Invalid values';
return false;
}
return true;
}
/**
* Shall return an error description if any
*
* @return string A description of the error
*/
public function getError()
{
return $this->error;
}
}

17
app/views/error/404.php Normal file
View File

@ -0,0 +1,17 @@
<!-- Error 404 yield file -->
<div class="outer">
<div class="inner">
<div class="title">
<h1>Error 404</h1>
</div>
<div class="text">
<p>The requested resource <?= $_SERVER['REQUEST_URI']; ?> was not found on the server.</p>
</div>
<div class="links">
<button type="button" class="button btn-col-contact" onclick="location.href = '{{ url('/') }}';">Go home</button>
</div>
</div>
</div>

View File

@ -0,0 +1,89 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Asatru PHP - Exception</title>
<style>
html, body {
width: 100%;
height: 100%;
background-color: rgb(30, 30, 30);
color: rgb(100, 100, 100);
}
.ex_box {
position: absolute;
width: 98%;
height: auto;
}
.ex_header {
position: relative;
margin-top: 5px;
margin-left: 10px;
margin-right: 10px;
font-size: 1.2em;
color: rgb(121, 73, 68);
}
.ex_msg {
position: relative;
margin-top: 5px;
margin-left: 10px;
margin-right: 10px;
font-size: 1.2em;
}
.ex_msg strong {
color: rgb(128, 0, 0);
}
.ex_trace_box {
position: relative;
margin-top: 35px;
margin-left: 10px;
margin-right: 10px;
margin-bottom: 35px;
border: 1px solid white;
}
.ex_trace_title {
position: relative;
margin-left: 5px;
}
.ex_trace_content {
position: relative;
margin-top: 15px;
margin-left: 15px;
margin-right: 15px;
margin-bottom: 15px;
font-size: 1.2em;
}
</style>
</head>
<body>
<div class="ex_box">
<div class="ex_header">
<h1><strong>Exception</strong> at <?= $exception->getFile(); ?>:<?= $exception->getLine(); ?></h1>
</div>
<div class="ex_msg">
Reported error: <strong><?= $exception->getMessage(); ?></strong>
</div>
<div class="ex_trace_box">
<div class="ex_trace_title">
Stack trace:
</div>
<div class="ex_trace_content">
<?= preg_replace("/\n/", '<br>', $exception->getTraceAsString()); ?>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Asatru PHP - Error 500</title>
<style>
html, body {
width: 100%;
height: 100%;
background-color: rgb(30, 30, 30);
color: rgb(100, 100, 100);
}
.outer {
position: relative;
width: 100%;
height: 100%;
}
.inner {
position: absolute;
margin: 0;
top: 50%;
left: 50%;
-ms-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
font-size: 2em;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
<strong>500</strong> | Internal server error
</div>
</div>
</body>
</html>

13
app/views/footer.php Normal file
View File

@ -0,0 +1,13 @@
<div class="footer">
<div class="columns">
<div class="column is-4"></div>
<div class="column is-4">
<div class="footer-frame">
<div class="footer-content">
&copy; {{ date('Y') }} by {{ env('APP_AUTHOR') }} | <a href="{{ env('APP_LINK_GITHUB') }}" title="GitHub"><i class="fab fa-github"></i></a>&nbsp;&nbsp;<a href="{{ env('APP_LINK_TWITTER') }}" title="Twitter"><i class="fab fa-twitter"></i></a>&nbsp;&nbsp;<a href="{{ env('APP_LINK_STEAM') }}" title="Steam"><i class="fab fa-steam"></i></a>
</div>
</div>
</div>
<div class="column is-4"></div>
</div>
</div>

668
app/views/generator.php Normal file
View File

@ -0,0 +1,668 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="{{ env('APP_AUTHOR') }}">
<meta name="description" content="{{ env('APP_DESCRIPTION') }}">
<meta name="keywords" content="{{ env('APP_KEYWORDS') }}">
<link rel="icon" type="image/png" href="{{ asset('img/logo.png') }}"/>
<link rel="stylesheet" type="text/css" href="{{ asset('css/bulma.css') }}"/>
<title>{{ env('APP_TITLE') }}</title>
<style>
html {
width: 100%;
height: 100%;
overflow-y: auto;
background-color: rgb(32, 32, 30);
}
body {
width: 100%;
height: 100%;
padding: 0;
}
#generator {
position: relative;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.generator-outer {
width: 100%;
height: 93%;
padding: 0;
}
.generator-outer h1 {
text-align: center;
color: rgb(200, 200, 200);
margin-bottom: 20px;
font-size: 1.3em;
}
.generator-outer p {
color: rgb(150, 150, 150);
margin-bottom: 20px;
padding-left: 10px;
padding-right: 10px;
text-align: center;
}
.generator-outer a:hover {
color: #3273dc;
text-decoration: underline;
}
.generator-inner {
position: absolute;
top: 50%;
left: 50%;
width: 90%;
transform: translate(-50%, -50%);
margin: 0;
}
.generator-headline {
width: 100%;
height: 50px;
margin-bottom: 53px;
background-color: rgb(85, 145, 245);
}
.generator-headline h1 {
position: relative;
top: 8px;
color: rgb(255, 255, 255);
}
.generator-menu-options {
text-align: center;
}
.generator-menu-options div {
margin-bottom: 15px;
}
.button-fixed-size {
min-width: 200px;
}
#generator-widget-app {
display: none;
}
#generator-widget-app h2 {
margin-bottom: 20px;
}
#generator-widget-app, #generator-widget-app label {
color: rgb(200, 200, 200);
}
#generator-widget-app input {
background-color: rgba(0, 0, 0, 0.1);
color: rgb(150, 150, 150);
}
#generator-widget-app form {
margin-bottom: 30px;
}
#widget-output-app {
display: none;
}
#widget-output-app pre {
background-color: rgb(55, 55, 55);
}
#widget-output-app code {
background-color: rgb(200, 200, 200);
}
#widget-output-codecopy-app {
display: none;
}
#generator-widget-server {
display: none;
}
#generator-widget-server h2 {
margin-bottom: 20px;
}
#generator-widget-server, #generator-widget-server label {
color: rgb(200, 200, 200);
}
#generator-widget-server input {
background-color: rgba(0, 0, 0, 0.1);
color: rgb(150, 150, 150);
}
#generator-widget-server form {
margin-bottom: 30px;
}
#widget-output-server {
display: none;
}
#widget-output-server pre {
background-color: rgb(55, 55, 55);
}
#widget-output-server code {
background-color: rgb(200, 200, 200);
}
#widget-output-codecopy-server {
display: none;
}
#generator-widget-user {
display: none;
}
#generator-widget-user h2 {
margin-bottom: 20px;
}
#generator-widget-user, #generator-widget-user label {
color: rgb(200, 200, 200);
}
#generator-widget-user input {
background-color: rgba(0, 0, 0, 0.1);
color: rgb(150, 150, 150);
}
#generator-widget-user form {
margin-bottom: 30px;
}
#widget-output-user {
display: none;
}
#widget-output-user pre {
background-color: rgb(55, 55, 55);
}
#widget-output-user code {
background-color: rgb(200, 200, 200);
}
#widget-output-codecopy-user {
display: none;
}
.footer-frame {
width: 100%;
height: 40px;
}
.footer-content {
text-align: center;
color: rgb(150, 150, 150);
}
.footer-content a {
color: rgb(130, 130, 130);
}
.footer-content a:hover {
color: rgb(150, 150, 150);
text-decoration: none;
}
</style>
@if (env('APP_DEBUG'))
<script src="{{ asset('js/vue.js') }}"></script>
@else
<script src="{{ asset('js/vue.min.js') }}"></script>
@endif
<script src="{{ asset('js/fontawesome.js') }}"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=app&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=server&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=user&version=v1"></script>
</head>
<body id="body" style="background-image: url('{{ asset('img/genbg.jpg') }}');">
<div id="generator">
<div class="generator-outer">
<div class="generator-headline">
<h1>SteamCards Widget Generator</h1>
</div>
<div id="infos">
<p>Please select a type of widget you want to create.</p>
<p>For more information about {{ env('APP_NAME') }} please visit <a href="{{ url('/') }}">{{ url('/') }}</a></p>
</div>
<div class="generator-inner" id="generator-inner">
<div class="generator-menu-options" id="generator-options">
<div><a class="button is-link is-outlined button-fixed-size" href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'none'; document.getElementById('generator-widget-app').style.display = 'unset'; window.setWidgetStyle(true); document.getElementById('footer').style.display = 'none'; document.getElementById('body').style.backgroundImage = 'unset'; document.getElementById('generator').style.backgroundColor = 'unset'; document.getElementById('infos').style.display = 'none';">Steam App Widget</a></div>
<div><a class="button is-link is-outlined button-fixed-size" href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'none'; document.getElementById('generator-widget-server').style.display = 'unset'; window.setWidgetStyle(true); document.getElementById('footer').style.display = 'none'; document.getElementById('body').style.backgroundImage = 'unset'; document.getElementById('generator').style.backgroundColor = 'unset'; document.getElementById('infos').style.display = 'none';">Steam Server Widget</a></div>
<div><a class="button is-link is-outlined button-fixed-size" href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'none'; document.getElementById('generator-widget-user').style.display = 'unset'; window.setWidgetStyle(true); document.getElementById('footer').style.display = 'none'; document.getElementById('body').style.backgroundImage = 'unset'; document.getElementById('generator').style.backgroundColor = 'unset'; document.getElementById('infos').style.display = 'none';">Steam User Widget</a></div>
</div>
<div id="generator-widget-app">
<a href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'unset'; document.getElementById('generator-widget-app').style.display = 'none'; document.getElementById('footer').style.display = 'unset'; document.getElementById('body').style.backgroundImage = 'url(\'{{ asset('img/genbg.jpg') }}\')'; document.getElementById('generator').style.backgroundColor = 'rgb(0, 0, 0, 0.5)'; document.getElementById('infos').style.display = 'initial'; window.setWidgetStyle(false);">Go Back</a><br/><br/>
<h2>Create Steam App Widget</h2>
<form>
<div class="field">
<label class="label">AppID</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-appid" value="12345" required/>
</div>
</div>
<div class="field">
<label class="label">Language</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-lang" value="english"/>
</div>
</div>
<div class="field">
<label class="label">Author</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-author" value="By :developer"/>
</div>
</div>
<div class="field">
<label class="label">Online Count</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-onlinecount" value=":count playing"/>
</div>
</div>
<div class="field">
<label class="label">Playtext</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-playtext" value="Play"/>
</div>
</div>
<div class="field">
<label class="label">Width</label>
<div class="control">
<input type="number" class="input" id="inp-widget-app-width" value=""/>
</div>
</div>
<div class="field">
<label class="label">Height</label>
<div class="control">
<input type="number" class="input" id="inp-widget-app-height" value=""/>
</div>
</div>
<div class="field">
<div class="control">
<a class="button is-success is-outlined" onclick="window.genAppWidget();">Generate</a>
</div>
</div>
</form>
<div id="widget-output-app">
<textarea id="widget-output-codecopy-app"></textarea>
<pre><code id="widget-code-app" class="language-html" onclick="window.copyToClipboard(document.getElementById('widget-output-codecopy-app').value); alert('Code copied to clipboard!');"></code></pre>
<br/><br/>
<div id="widget-sample-app"></div>
<br/><br/><br/>
</div>
</div>
<div id="generator-widget-server">
<a href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'unset'; document.getElementById('generator-widget-server').style.display = 'none'; document.getElementById('footer').style.display = 'unset'; document.getElementById('body').style.backgroundImage = 'url(\'{{ asset('img/genbg.jpg') }}\')'; document.getElementById('generator').style.backgroundColor = 'rgb(0, 0, 0, 0.5)'; document.getElementById('infos').style.display = 'initial'; window.setWidgetStyle(false);">Go Back</a><br/><br/>
<h2>Create Steam Server Widget</h2>
<form>
<div class="field">
<label class="label">Address</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-addr" value="ip:port" required/>
</div>
</div>
<div class="field">
<label class="label">Header</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-header" value=""/>
</div>
</div>
<div class="field">
<label class="label">Bots</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-bots" value=":count bots"/>
</div>
</div>
<div class="field">
<label class="label">Secure Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-secure-yes" value="secure"/>
</div>
</div>
<div class="field">
<label class="label">Insecure text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-secure-no" value="insecure"/>
</div>
</div>
<div class="field">
<label class="label">Dedicated Hosting Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-hosting-dedicated" value="dedicated"/>
</div>
</div>
<div class="field">
<label class="label">Listen Hosting Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-hosting-listen" value="listen"/>
</div>
</div>
<div class="field">
<label class="label">Join text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-server-join" value="Join"/>
</div>
</div>
<div class="field">
<label class="label">Width</label>
<div class="control">
<input type="number" class="input" id="inp-widget-server-width" value=""/>
</div>
</div>
<div class="field">
<label class="label">Height</label>
<div class="control">
<input type="number" class="input" id="inp-widget-server-height" value=""/>
</div>
</div>
<div class="field">
<div class="control">
<a class="button is-success is-outlined" onclick="window.genServerWidget();">Generate</a>
</div>
</div>
</form>
<div id="widget-output-server">
<textarea id="widget-output-codecopy-server"></textarea>
<pre><code id="widget-code-server" class="language-html" onclick="window.copyToClipboard(document.getElementById('widget-output-codecopy-server').value); alert('Code copied to clipboard!');"></code></pre>
<br/><br/>
<div id="widget-sample-server"></div>
<br/><br/><br/>
</div>
</div>
<div id="generator-widget-user">
<a href="javascript:void(0);" onclick="document.getElementById('generator-options').style.display = 'unset'; document.getElementById('generator-widget-user').style.display = 'none'; document.getElementById('footer').style.display = 'unset'; document.getElementById('body').style.backgroundImage = 'url(\'{{ asset('img/genbg.jpg') }}\')'; document.getElementById('generator').style.backgroundColor = 'rgb(0, 0, 0, 0.5)'; document.getElementById('infos').style.display = 'initial'; window.setWidgetStyle(false);">Go Back</a><br/><br/>
<h2>Create Steam User Widget</h2>
<form>
<div class="field">
<label class="label">SteamID</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-steamid" value="12345" required/>
</div>
</div>
<div class="field">
<label class="label">Header</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-header" value=""/>
</div>
</div>
<div class="field">
<label class="label">Online Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-online-yes" value="online"/>
</div>
</div>
<div class="field">
<label class="label">Offline Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-online-no" value="offline"/>
</div>
</div>
<div class="field">
<label class="label">Member Since Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-membersince" value="Member since: :year-:month-:day"/>
</div>
</div>
<div class="field">
<label class="label">View Text</label>
<div class="control">
<input type="text" class="input" id="inp-widget-user-viewtext" value="View"/>
</div>
</div>
<div class="field">
<label class="label">Width</label>
<div class="control">
<input type="number" class="input" id="inp-widget-user-width" value=""/>
</div>
</div>
<div class="field">
<label class="label">Height</label>
<div class="control">
<input type="number" class="input" id="inp-widget-user-height" value=""/>
</div>
</div>
<div class="field">
<div class="control">
<a class="button is-success is-outlined" onclick="window.genUserWidget();">Generate</a>
</div>
</div>
</form>
<div id="widget-output-user">
<textarea id="widget-output-codecopy-user"></textarea>
<pre><code id="widget-code-user" class="language-html" onclick="window.copyToClipboard(document.getElementById('widget-output-codecopy-user').value); alert('Code copied to clipboard!');"></code></pre>
<br/><br/>
<div id="widget-sample-user"></div>
<br/><br/><br/>
</div>
</div>
</div>
</div>
<div class="footer-frame" id="footer">
<div class="footer-content">
&copy; {{ date('Y') }} by {{ env('APP_AUTHOR') }} | <a href="{{ env('APP_LINK_GITHUB') }}" title="GitHub"><i class="fab fa-github"></i></a>&nbsp;&nbsp;<a href="{{ env('APP_LINK_TWITTER') }}" title="Twitter"><i class="fab fa-twitter"></i></a>&nbsp;&nbsp;<a href="{{ env('APP_LINK_STEAM') }}" title="Steam"><i class="fab fa-steam"></i></a>
</div>
</div>
<div id="app" style="display: none;"></div>
</div>
<script src="{{ asset('js/app.js') }}"></script>
<script>
window.genAppWidget = function() {
let appid = document.getElementById('inp-widget-app-appid').value;
let lang = document.getElementById('inp-widget-app-lang').value;
let author = document.getElementById('inp-widget-app-author').value;
let playtext = document.getElementById('inp-widget-app-playtext').value;
let onlinecount = document.getElementById('inp-widget-app-onlinecount').value;
let width = document.getElementById('inp-widget-app-width').value;
let height = document.getElementById('inp-widget-app-height').value;
document.getElementById('widget-output-app').style.display = 'unset';
let codeOutput = `
&lt;script src="{{ url('/api/resource/query?type=js&module=app&version=v1') }}"&gt;&lt;/script&gt;
&lt;steam-app appid="` + appid + `" lang="` + lang + `" author="` + author + `" playtext="` + playtext + `" onlinecount="` + onlinecount + `" width="` + width + `" height="` + height + `"&gt;&lt;/steam-app&gt;
`;
document.getElementById('widget-code-app').innerHTML = codeOutput;
document.getElementById('widget-output-codecopy-app').value = codeOutput;
while ((document.getElementById('widget-output-codecopy-app').value.indexOf('&lt;') >= 0) || (document.getElementById('widget-output-codecopy-app').value.indexOf('&gt;') >= 0)) {
document.getElementById('widget-output-codecopy-app').value = document.getElementById('widget-output-codecopy-app').value.replace('&lt;', '<').replace('&gt;', '>')
}
document.getElementById('widget-sample-app').innerHTML = '';
let sampleCard = new SteamApp('#widget-sample-app', {
appid: appid,
lang: lang,
playtext: playtext,
onlinecount: onlinecount,
width: width,
height: height
});
window.hljs.highlightAll();
setTimeout(function(){
window.scrollBy(0, 600);
}, 1500);
};
window.genServerWidget = function() {
let addr = document.getElementById('inp-widget-server-addr').value;
let header = document.getElementById('inp-widget-server-header').value;
let bots = document.getElementById('inp-widget-server-bots').value;
let secYes = document.getElementById('inp-widget-server-secure-yes').value;
let secNo = document.getElementById('inp-widget-server-secure-no').value;
let dedicated = document.getElementById('inp-widget-server-hosting-dedicated').value;
let listen = document.getElementById('inp-widget-server-hosting-listen').value;
let playtext = document.getElementById('inp-widget-server-join').value;
let width = document.getElementById('inp-widget-server-width').value;
let height = document.getElementById('inp-widget-server-height').value;
document.getElementById('widget-output-server').style.display = 'unset';
let codeOutput = `
&lt;script src="{{ url('/api/resource/query?type=js&module=server&version=v1') }}"&gt;&lt;/script&gt;
&lt;steam-server addr="` + addr + `" header="` + header + `" secure-yes="` + secYes + `" secure-no="` + secNo + `" hosting-dedicated="` + dedicated + `" hosting-listen="` + listen + `" playtext="` + playtext + `" width="` + width + `" height="` + height + `"&gt;&lt;/steam-server&gt;
`;
document.getElementById('widget-code-server').innerHTML = codeOutput;
document.getElementById('widget-output-codecopy-server').value = codeOutput;
while ((document.getElementById('widget-output-codecopy-server').value.indexOf('&lt;') >= 0) || (document.getElementById('widget-output-codecopy-server').value.indexOf('&gt;') >= 0)) {
document.getElementById('widget-output-codecopy-server').value = document.getElementById('widget-output-codecopy-server').value.replace('&lt;', '<').replace('&gt;', '>')
}
document.getElementById('widget-sample-server').innerHTML = '';
let sampleCard = new SteamServer('#widget-sample-server', {
addr: addr,
header: header,
playtext: playtext,
bots: bots,
secure_yes: secYes,
secure_no: secNo,
hosting_dedicated: dedicated,
hosting_listen: listen,
width: width,
height: height
});
window.hljs.highlightAll();
setTimeout(function(){
window.scrollBy(0, 600);
}, 1500);
};
window.genUserWidget = function() {
let steamid = document.getElementById('inp-widget-user-steamid').value;
let header = document.getElementById('inp-widget-user-header').value;
let online = document.getElementById('inp-widget-user-online-yes').value;
let offline = document.getElementById('inp-widget-user-online-no').value;
let membersince = document.getElementById('inp-widget-user-membersince').value;
let viewtext = document.getElementById('inp-widget-user-viewtext').value;
let width = document.getElementById('inp-widget-user-width').value;
let height = document.getElementById('inp-widget-user-height').value;
document.getElementById('widget-output-user').style.display = 'unset';
let codeOutput = `
&lt;script src="{{ url('/api/resource/query?type=js&module=user&version=v1') }}"&gt;&lt;/script&gt;
&lt;steam-user steamid="` + steamid + `" header="` + header + `" online-yes="` + online + `" online-no="` + offline + `" member-since="` + membersince + `" viewtext="` + viewtext + `" width="` + width + `" height="` + height + `"&gt;&lt;/steam-user&gt;
`;
document.getElementById('widget-code-user').innerHTML = codeOutput;
document.getElementById('widget-output-codecopy-user').value = codeOutput;
while ((document.getElementById('widget-output-codecopy-user').value.indexOf('&lt;') >= 0) || (document.getElementById('widget-output-codecopy-user').value.indexOf('&gt;') >= 0)) {
document.getElementById('widget-output-codecopy-user').value = document.getElementById('widget-output-codecopy-user').value.replace('&lt;', '<').replace('&gt;', '>')
}
document.getElementById('widget-sample-user').innerHTML = '';
let sampleCard = new SteamUser('#widget-sample-user', {
steamid: steamid,
header: header,
online_yes: online,
online_no: offline,
member_since: membersince,
viewtext: viewtext,
width: width,
height: height
});
window.hljs.highlightAll();
setTimeout(function(){
window.scrollBy(0, 600);
}, 1500);
};
window.setWidgetStyle = function(flag) {
if (flag) {
document.getElementById('generator-inner').style.top = 'unset';
document.getElementById('generator-inner').style.transform = 'translate(-50%, -0%)';
document.getElementById('generator-inner').style.overflowY = 'hidden';
} else {
document.getElementById('generator-inner').style.top = '50%';
document.getElementById('generator-inner').style.transform = 'translate(-50%, -50%)';
document.getElementById('generator-inner').style.overflowY = 'unset';
}
};
window.copyToClipboard = function(text) {
const el = document.createElement('textarea');
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
};
</script>
</body>
</html>

551
app/views/index.php Normal file
View File

@ -0,0 +1,551 @@
<div class="content-section content-centered content-top-margin">
<h1>{{ env('APP_NAME') }}</h1>
<h2>{{ env('APP_DESCRIPTION') }}</h2>
</div>
<div class="content-section">
<a name="about"></a><br/><br/>
<h3>About</h3>
<p>
SteamCards is a clientside web component that offers an easy way to integrate Steam Cards of various Steam
entities into your website. Therefore you only need very few code in order to render Steam Cards into your document.
</p>
<p>
SteamCards is used via JavaScript. Since JavaScript is supported by all major browser per default it is
platform independent and compatible.
</p>
<p>
The following Widgets are currently available:<br/>
<ul>
<li><a href="#steam-app">Steam App Widget</a></li>
<li><a href="#steam-server">Steam Server Widget</a></li>
<li><a href="#steam-user">Steam User Widget</a></li>
</ul>
</p>
<p>
You can use SteamCards by referencing the neccessary JavaScript files from the official SteamCards server as follows:<br/>
<pre>
<code class="language-html">
&lt;script src="{{ url('/api/resource/query?type=js&module=STEAM_CARDS_MODULE&version=v1') }}"&gt;&lt;/script&gt;
</code>
</pre>
<br/>
<i>STEAM_CARDS_MODULE</i> can either be <b>app</b> for the Steam App widget, <b>server</b> for the Steam Server widget or
<b>user</b> for the Steam User widget.
</p>
@if (env('APP_SHOWNPMUSAGE', false))
<p>
You can also use NPM to install the package. Please visit the NPM page of the package in order to get instruction details:<br/>
<br/>
<a href="{{ env('APP_NPMPACKAGEURL') }}">{{ env('APP_NPMPACKAGEURL') }}</a>
</p>
@endif
<hr/>
</div>
<div class="content-section">
<a name="steam-app"></a><br/><br/>
<h3>Steam App</h3>
<p>
When referenced the required Steam App module, the minimum code to render a card is as follows:<br/>
<pre>
<code class="language-html">
&lt;steam-app appid="620"&gt;&lt;/steam-app&gt;
</code>
</pre>
<br/><br/>
This renders the following card:<br/>
<steam-app appid="620"></steam-app>
</p>
<p>
<br/>You can define these options:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Attribute</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr class="tr-colored">
<td>appid</td>
<td>Specifies the ID of a Steam game/app</td>
</tr>
<tr>
<td>lang</td>
<td>Specifies the language of the localized Steam data</td>
</tr>
<tr class="tr-colored">
<td>onlinecount</td>
<td>If specified this will be the text for the online count. Use <b>:count</b> to dynamically insert the actual products player/user count.</td>
</tr>
<tr>
<td>playtext</td>
<td>Specifies the text of the button that eventually links to the Steam products store page</td>
</tr>
<tr class="tr-colored">
<td>author</td>
<td>Specify a text that is displayed as the author of the product. You can use <b>:developer</b> and <b>:publisher</b> to dynamically insert the products developer and publisher names</td>
</tr>
<tr>
<td>width</td>
<td>Specify the width of the card</td>
</tr>
<tr class="tr-colored">
<td>height</td>
<td>Specify the height of the card</td>
</tr>
<tr>
<td>style-border / style.border</td>
<td>Specify border rounding: Either none, small or max</td>
</tr>
<tr class="tr-colored">
<td>style-shadow / style.shadow</td>
<td>You can specify false to prevent displaying box shadow or true to enable (default)</td>
</tr>
<tr>
<td>style-color-background / style.colorBackground</td>
<td>Specify a CSS value for the background color</td>
</tr>
<tr class="tr-colored">
<td>style-color-title / style.colorTitle</td>
<td>Specify a CSS value for the title color</td>
</tr>
<tr>
<td>style-color-description / style.colorDescription</td>
<td>Specify a CSS value for the description color</td>
</tr>
<tr class="tr-colored">
<td>style-color-author / style.colorAuthor</td>
<td>Specify a CSS value for the author color</td>
</tr>
<tr>
<td>style-color-onlinecount / style.colorOnlinecount</td>
<td>Specify a CSS value for the online count color</td>
</tr>
<tr class="tr-colored">
<td>style-hideimage / style.hideimage</td>
<td>Specify whether the card image shall be hidden or not</td>
</tr>
</tbody>
</table>
</p>
<p>
You can also dynamically create Steam App cards via JavaScript:<br/>
<pre>
<code class="language-html">
&lt;div id="app-card"&gt;&lt;/div&gt;
&lt;script&gt;
document.addEventListener('DOMContentLoaded', function() {
let card = new SteamApp('#app-card', {
appid: '620',
//You can specify the same attributes as shown in the table above
});
});
&lt;/script&gt;
</code>
</pre>
</p>
<p>
<br/>The following methods are available for a Steam App element / object:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Method</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr class="tr-colored">
<td>updateCard()</td>
<td>Updates the card data and displays them</td>
</tr>
<tr>
<td>changeLang(lang, playtext, author, onlinecount)</td>
<td>Changes the language of the card using the given information</td>
</tr>
<tr class="tr-colored">
<td>setImageVisibility(visibility)</td>
<td>Sets the card image visibility</td>
</tr>
<tr>
<td>remove()</td>
<td>Removes the card from the document</td>
</tr>
</tbody>
</table>
</p>
<hr/>
</div>
<div class="content-section">
<a name="steam-server"></a><br/><br/>
<h3>Steam Server</h3>
<p>
When referenced the required Steam Server module, the minimum code to render a card is as follows:<br/>
<pre>
<code class="language-html">
&lt;steam-server addr="ip:port"&gt;&lt;/steam-server&gt;
</code>
</pre>
<br/><br/>
This renders the following card:<br/>
<steam-server addr="ip:port"></steam-server>
</p>
<p>
<br/>You can define these options:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Attribute</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr class="tr-colored">
<td>addr</td>
<td>Specifies the address of the server using format <b>ip</b>:<b>port</b></td>
</tr>
<tr>
<td>header</td>
<td>If you want to render the card with a header image you may specify the URL to an image here</td>
</tr>
<tr class="tr-colored">
<td>bots</td>
<td>Specify the text for the bot info. Use :count to render the actual bot count</td>
</tr>
<tr>
<td>secure_yes</td>
<td>Specifies the text that is displayed if the server is a secure server</td>
</tr>
<tr class="tr-colored">
<td>secure_no</td>
<td>Specifies the text that is displayed if the server is not a secure server</td>
</tr>
<tr>
<td>hosting_dedicated</td>
<td>Specifies the text that is displayed if the server is a dedicated server</td>
</tr>
<tr class="tr-colored">
<td>hosting_listen</td>
<td>Specifies the text that is displayed if the server is a listen server</td>
</tr>
<tr>
<td>playtext</td>
<td>Specifies the text of the button that issues a connection to the server</td>
</tr>
<tr class="tr-colored">
<td>width</td>
<td>Specify the width of the card</td>
</tr>
<tr>
<td>height</td>
<td>Specify the height of the card</td>
</tr>
<tr class="tr-colored">
<td>style-border / style.border</td>
<td>Specify border rounding: Either none, small or max</td>
</tr>
<tr>
<td>style-shadow / style.shadow</td>
<td>You can specify false to prevent displaying box shadow or true to enable (default)</td>
</tr>
<tr class="tr-colored">
<td>style-color-background / style.colorBackground</td>
<td>Specify a CSS value for the background color</td>
</tr>
<tr>
<td>style-color-text-bright / style.colorTextBright</td>
<td>Specify a CSS value for the bright texts</td>
</tr>
<tr class="tr-colored">
<td>style-color-text-dark / style.colorTextDark</td>
<td>Specify a CSS value for the dark texts</td>
</tr>
</tbody>
</table>
</p>
<p>
You can also dynamically create Steam Server cards via JavaScript:<br/>
<pre>
<code class="language-html">
&lt;div id="server-card"&gt;&lt;/div&gt;
&lt;script&gt;
document.addEventListener('DOMContentLoaded', function() {
let card = new SteamServer('#server-card', {
addr: 'ip:port',
//You can specify the same attributes as shown in the table above
});
});
&lt;/script&gt;
</code>
</pre>
</p>
<p>
<br/>The following methods are available for a Steam Server element / object:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Method</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr class="tr-colored">
<td>updateCard()</td>
<td>Updates the card data and displays them</td>
</tr>
<tr>
<td>changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext)</td>
<td>Changes the language of the card using the given information</td>
</tr>
<tr class="tr-colored">
<td>setImageVisibility(visibility)</td>
<td>Sets the card image visibility</td>
</tr>
<tr>
<td>remove()</td>
<td>Removes the card from the document</td>
</tr>
</tbody>
</table>
</p>
<hr/>
</div>
<div class="content-section">
<a name="steam-user"></a><br/><br/>
<h3>Steam User</h3>
<p>
When referenced the required Steam User module, the minimum code to render a card is as follows:<br/>
<pre>
<code class="language-html">
&lt;steam-user steamid="id"&gt;&lt;/steam-user&gt;
</code>
</pre>
<br/><br/>
This renders the following card:<br/>
<steam-user steamid="steamid"></steam-user>
</p>
<p>
<br/>You can define these options:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Attribute</strong></td>
<td><strong>Value</strong></td>
</tr>
<tr class="tr-colored">
<td>steamid</td>
<td>Specifies the SteamID of the Steam user</td>
</tr>
<tr>
<td>header</td>
<td>If you want to render the card with a header image you may specify the URL to an image here</td>
</tr>
<tr class="tr-colored">
<td>online_yes</td>
<td>Specifies the text that is displayed if the user is currently online</td>
</tr>
<tr>
<td>online_no</td>
<td>Specifies the text that is displayed if the user is not currently online</td>
</tr>
<tr class="tr-colored">
<td>member_since</td>
<td>Specifies the text and format of the info that shows since when the user account is registered. Use <b>:year</b>, <b>:month</b> and <b>:day</b> to format the date.</td>
</tr>
<tr>
<td>viewtext</td>
<td>Specifies the text of the button which can be used to go to the users Steam Community profile</td>
</tr>
<tr class="tr-colored">
<td>width</td>
<td>Specify the width of the card</td>
</tr>
<tr>
<td>height</td>
<td>Specify the height of the card</td>
</tr>
<tr class="tr-colored">
<td>style-border / style.border</td>
<td>Specify border rounding: Either none, small or max</td>
</tr>
<tr>
<td>style-shadow / style.shadow</td>
<td>You can specify false to prevent displaying box shadow or true to enable (default)</td>
</tr>
<tr class="tr-colored">
<td>style-color-background / style.colorBackground</td>
<td>Specify a CSS value for the background color</td>
</tr>
<tr>
<td>style-color-text-bright / style.colorTextBright</td>
<td>Specify a CSS value for the bright texts</td>
</tr>
<tr class="tr-colored">
<td>style-color-text-dark / style.colorTextDark</td>
<td>Specify a CSS value for the dark texts</td>
</tr>
</tbody>
</table>
</p>
<p>
You can also dynamically create Steam User cards via JavaScript:<br/>
<pre>
<code class="language-html">
&lt;div id="user-card"&gt;&lt;/div&gt;
&lt;script&gt;
document.addEventListener('DOMContentLoaded', function() {
let card = new SteamUser('#user-card', {
steamid: 'id',
//You can specify the same attributes as shown in the table above
});
});
&lt;/script&gt;
</code>
</pre>
</p>
<p>
<br/>The following methods are available for a Steam User element / object:<br/>
<table>
<thead>
<tr></tr>
<tr></tr>
</thead>
<tbody>
<tr>
<td><strong>Method</strong></td>
<td><strong>Description</strong></td>
</tr>
<tr class="tr-colored">
<td>updateCard()</td>
<td>Updates the card data and displays them</td>
</tr>
<tr>
<td>changeLang(online_yes, online_no, member_since, viewtext)</td>
<td>Changes the language of the card using the given information</td>
</tr>
<tr class="tr-colored">
<td>setImageVisibility(visibility)</td>
<td>Sets the card image visibility</td>
</tr>
<tr>
<td>remove()</td>
<td>Removes the card from the document</td>
</tr>
</tbody>
</table>
</p>
</div>

60
app/views/layout.php Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="{{ getLocale() }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="{{ env('APP_AUTHOR') }}">
<meta name="description" content="{{ env('APP_DESCRIPTION') }}">
<meta name="keywords" content="{{ env('APP_KEYWORDS') }}">
<link rel="icon" type="image/png" href="{{ asset('img/logo.png') }}"/>
<link rel="stylesheet" type="text/css" href="{{ asset('css/bulma.css') }}"/>
<link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}"/>
<title>{{ env('APP_TITLE') }}</title>
@if (env('APP_DEBUG'))
<script src="{{ asset('js/vue.js') }}"></script>
@else
<script src="{{ asset('js/vue.min.js') }}"></script>
@endif
<script src="{{ asset('js/fontawesome.js') }}"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=app&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=server&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=user&version=v1"></script>
</head>
<body>
<div id="app">
@include('navbar.php')
<div class="container">
<div class="columns">
<div class="column is-2"></div>
<div class="column is-8">
{%content%}
<div class="scroll-to-top">
<div class="scroll-to-top-inner">
<a href="javascript:void(0);" onclick="window.scroll({top: 0, left: 0, behavior: 'smooth'});"><i class="fas fa-arrow-up fa-2x up-color"></i></a>
</div>
</div>
</div>
<div class="column is-2"></div>
</div>
</div>
@include('footer.php')
</div>
<script src="{{ asset('js/app.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
window.vue.initNavBar();
});
</script>
</body>
</html>

47
app/views/navbar.php Normal file
View File

@ -0,0 +1,47 @@
<nav class="navbar is-light is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item navbar-item-brand is-font-title" href="{{ url('/') }}">
<img src="{{ asset('img/logo.png') }}"/>&nbsp;{{ env('APP_NAME') }}
</a>
<a id="burger-button" role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" href="{{ url('/#about') }}" onclick="document.getElementById('burger-button').click(); return true;">
About
</a>
<a class="navbar-item" href="{{ url('/#steam-app') }}" onclick="document.getElementById('burger-button').click(); return true;">
Steam App
</a>
<a class="navbar-item" href="{{ url('/#steam-server') }}" onclick="document.getElementById('burger-button').click(); return true;">
Steam Server
</a>
<a class="navbar-item" href="{{ url('/#steam-user') }}" onclick="document.getElementById('burger-button').click(); return true;">
Steam User
</a>
</div>
<div class="navbar-end">
<div class="navbar-item">
<img src="https://img.shields.io/github/forks/{{ env('APP_PACKAGE') }}?style=social"/>
</div>
<div class="navbar-item">
<img src="https://img.shields.io/github/issues/{{ env('APP_PACKAGE') }}?style=social"/>
</div>
<div class="navbar-item">
<img src="https://img.shields.io/github/downloads/{{ env('APP_PACKAGE') }}/total?style=social"/>
</div>
</div>
</div>
</nav>

43
asatru Normal file
View File

@ -0,0 +1,43 @@
<?php
/*
Asatru PHP (dnyAsatruPHP) developed by Daniel Brendel
(C) 2019 - 2022 by Daniel Brendel
Version: 1.0
Contact: dbrendel1988<at>gmail<dot>com
GitHub: https://github.com/danielbrendel/
Released under the MIT license
*/
//Set application root directory path
define('ASATRU_APP_ROOT', __DIR__);
//Require constants
require_once __DIR__ . '/vendor/danielbrendel/asatru-php-framework/src/constants.php';
//Require .env config management
require_once __DIR__ . '/vendor/danielbrendel/asatru-php-framework/src/dotenv.php';
//Parse .env file if it exists
if (file_exists('.env')) {
env_parse('.env');
}
//Include CLI handler
require_once __DIR__ . '/vendor/danielbrendel/asatru-php-framework/src/console.php';
//Require database handler
require_once __DIR__ . '/vendor/danielbrendel/asatru-php-framework/src/database.php';
//Process further if in debug mode
if ((isset($_ENV['APP_DEBUG'])) && ($_ENV['APP_DEBUG'])) {
Asatru\Console\handleInput($argv);
} else {
echo "\033[31mCLI tool is only available in debug mode\033[39m\n";
}
//Success, we can end script execution
exit(0);

39
build_ver.bat Normal file
View File

@ -0,0 +1,39 @@
@echo off
cls
set /p ver=Please enter the version:
echo "Using version: %ver%"
mkdir "%~dp0public\js\steamcards\%ver%"
mkdir "%~dp0public\css\steamcards\%ver%"
del "%~dp0public\js\steamcards\%ver%\steam_app.js"
del "%~dp0public\css\steamcards\%ver%\steam_app.css"
del "%~dp0public\js\steamcards\%ver%\steam_server.js"
del "%~dp0public\css\steamcards\%ver%\steam_server.css"
del "%~dp0public\js\steamcards\%ver%\steam_user.js"
del "%~dp0public\css\steamcards\%ver%\steam_user.css"
xcopy "%~dp0app\resources\js\steam_app.dev.js" "%~dp0public\js\steamcards\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_app.dev.css" "%~dp0public\css\steamcards\%ver%\" /Y
xcopy "%~dp0app\resources\js\steam_server.dev.js" "%~dp0public\js\steamcards\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_server.dev.css" "%~dp0public\css\steamcards\%ver%\" /Y
xcopy "%~dp0app\resources\js\steam_user.dev.js" "%~dp0public\js\steamcards\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_user.dev.css" "%~dp0public\css\steamcards\%ver%\" /Y
ren "%~dp0public\js\steamcards\%ver%\steam_app.dev.js" "steam_app.js"
ren "%~dp0public\css\steamcards\%ver%\steam_app.dev.css" "steam_app.css"
ren "%~dp0public\js\steamcards\%ver%\steam_server.dev.js" "steam_server.js"
ren "%~dp0public\css\steamcards\%ver%\steam_server.dev.css" "steam_server.css"
ren "%~dp0public\js\steamcards\%ver%\steam_user.dev.js" "steam_user.js"
ren "%~dp0public\css\steamcards\%ver%\steam_user.dev.css" "steam_user.css"
echo "Job done"
pause

31
composer.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "danielbrendel/asatru-php",
"version": "1.0",
"description": "A lightweight PHP framework",
"type": "project",
"license": "MIT",
"authors": [
{
"name": "Daniel Brendel",
"email": "dbrendel1988@gmail.com"
}
],
"keywords": [
"asatru",
"framework",
"php"
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": ">=7.4.6",
"danielbrendel/asatru-php-framework": "^1.0",
"phpmailer/phpmailer": "^6.1",
"nesbot/carbon": "^2.0"
},
"scripts": {
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
]
}
}

2278
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/documentation.pdf Normal file

Binary file not shown.

1466
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "asatruphp",
"version": "1.0.0",
"description": "(C) 2019 - 2022 by Daniel Brendel",
"main": "index.js",
"directories": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/danielbrendel/dnyAsatruPHP-App.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/danielbrendel/dnyAsatruPHP-App/issues"
},
"homepage": "https://github.com/danielbrendel/dnyAsatruPHP-App#readme",
"devDependencies": {
"css-loader": "^5.2.7",
"sass": "^1.54.3",
"sass-loader": "^10.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"dependencies": {
"highlight.js": "^11.6.0",
"style-loader": "^1.2.1"
}
}

16
phpunit.xml Normal file
View File

@ -0,0 +1,16 @@
<phpunit
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
bootstrap="app/tests/bootstrap.php"
>
<testsuites>
<testsuite name="Testcases">
<directory>app/tests</directory>
</testsuite>
</testsuites>
</phpunit>

21
public/.htaccess Normal file
View File

@ -0,0 +1,21 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

159
public/css/app.css Normal file
View File

@ -0,0 +1,159 @@
/*
app.scss
*/
html, body {
width: 100%;
height: auto;
margin: 0 auto;
}
body {
overflow-x: hidden;
}
@media screen and (min-width: 1088px) {
.navbar-start {
flex-grow: 1;
justify-content: center;
transform: translate(11%, -0%)
}
}
.is-font-title {
font-family: 'Helvetica', Verdana, Arial, sans-serif;
font-size: 20px;
}
.content-section {
padding: 20px;
}
.content-centered {
text-align: center;
}
.content-top-margin {
margin-top: 90px;
}
@media screen and (max-width: 1088px) {
.content-top-margin {
margin-top: 58px;
}
}
.content-section h1 {
font-size: 2.0em;
margin-bottom: 10px;
}
.content-section h2 {
font-size: 1.5em;
color: rgb(100, 100, 100);
}
.content-section h3 {
font-size: 1.2em;
color: rgb(100, 100, 100);
margin-bottom: 30px;
}
.content-section p {
margin-bottom: 20px;
}
.content-section a {
color: #3273dc;
}
.content-section a:hover {
color: #3273dc;
text-decoration: underline;
}
.content-section pre {
padding: unset;
margin-top: -15px;
margin-bottom: -61px;
background-color: unset;
}
.content-section code {
background-color: rgb(230, 230, 230);
border-radius: 4px;
}
.content-section ul {
list-style: square;
}
.content-section li {
margin-left: 15px;
}
.content-section table {
margin-bottom: 40px;
}
.content-section tbody {
border: 1px solid #ccc;
}
.content-section td {
padding: 15px;
}
.tr-colored {
background-color: rgb(200, 200, 200);
}
.content-section hr {
background-color: rgb(200, 200, 200);
}
.scroll-to-top {
position: fixed;
z-index: 3;
bottom: 12px;
right: 12px;
}
.scroll-to-top-inner {
background-color: rgb(100, 100, 100);
border-radius: 50%;
padding: 12px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
.scroll-to-top-inner a {
color: rgb(200, 200, 200);
}
.scroll-to-top-inner a:hover {
color: rgb(200, 200, 200);
}
.footer {
width: 100%;
color: rgb(100, 100, 100);
background-color: rgb(235, 235, 235);
padding: 1rem 1.5rem 1rem;
}
.footer-frame {
width: 100%;
}
.footer-content {
text-align: center;
}
.footer-content a {
color: rgb(130, 130, 130);
}
.footer-content a:hover {
color: rgb(150, 150, 150);
text-decoration: none;
}

11406
public/css/bulma.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
.steam-app {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-app-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-app-infos {
position: relative;
padding: 15px;
}
.steam-app-title {
width: 100%;
margin-bottom: 10px;
}
.steam-app-title-name {
display: inline-block;
color: rgb(220, 220, 220);
font-size: 1.1em;
font-family: Verdana, Arial, sans-serif;
}
.steam-app-title-count {
position: relative;
display: inline-block;
top: 5px;
color: rgb(55, 230, 111);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
float: right;
}
.steam-app-description {
width: 100%;
color: rgb(150, 150, 150);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
margin-bottom: 20px;
}
.steam-app-footer {
width: 100%;
margin-bottom: 10px;
}
.steam-app-footer-author {
display: inline-block;
color: rgb(200, 200, 200);
font-family: Verdana, Arial, sans-serif;
font-size: 0.8em;
}
.steam-app-footer-button {
display: inline-block;
float: right;
}
.steam-app-footer-button a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-app-footer-button a:hover {
color: rgb(250, 250, 250);
}

View File

@ -0,0 +1,103 @@
.steam-server {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-server-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-server-infos {
position: relative;
padding: 15px;
}
.steam-server-title {
}
.steam-server-title-left {
position: relative;
display: inline-block;
}
.steam-server-title-left-addr {
color: rgb(200, 200, 200);
}
.steam-server-title-left-name {
color: rgb(150, 150, 150);
font-size: 0.8em;
}
.steam-server-title-right {
position: relative;
display: inline-block;
float: right;
}
.steam-server-title-right-count {
color: rgb(130, 130, 130);
font-size: 0.7em;
}
.steam-server-title-right-bots {
color: rgb(130, 130, 130);
font-size: 0.7em;
}
.steam-server-gameinfo {
position: relative;
display: inline-block;
margin-top: 10px;
margin-bottom: 10px;
}
.steam-server-gameinfo-item {
color: rgb(150, 150, 150);
font-size: 0.65em;
}
.steam-server-gameinfo-item-green {
color: rgb(85, 190, 111);
}
.steam-server-gameinfo-item-red {
color: rgb(179, 115, 115);
}
.steam-server-action {
position: relative;
display: inline-block;
float: right;
margin-top: 10px;
margin-bottom: 10px;
}
.steam-server-action a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-server-action a:hover {
color: rgb(250, 250, 250);
}

View File

@ -0,0 +1,97 @@
.steam-user {
position: relative;
max-width: 360px;
background-color: rgb(22, 32, 45);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 25px;
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
}
.steam-user-image {
position: relative;
width: 100%;
height: 176px;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.steam-user-infos {
position: relative;
padding: 15px;
}
.steam-user-infos-left {
position: relative;
display: inline-block;
}
.steam-user-infos-left-avatar {
position: relative;
display: inline-block;
}
.steam-user-infos-left-avatar img {
width: 64px;
height: 64px;
border-radius: 50%;
}
.steam-user-infos-left-text {
position: relative;
display: inline-block;
top: -16px;
margin-left: 10px;
}
.steam-user-infos-left-text-name {
color: rgb(200, 200, 200);
}
.steam-user-infos-left-text-since {
color: rgb(150, 150, 150);
font-size: 0.8em;
}
.steam-user-infos-right {
position: relative;
display: inline-block;
margin-right: 5px;
float: right;
}
.steam-user-infos-right-online {
position: relative;
top: 11px;
color: rgb(100, 100, 100);
font-size: 0.8em;
}
.steam-user-infos-right-online-green {
color: rgb(85, 190, 111);
}
.steam-user-infos-right-view {
position: relative;
top: 15px;
}
.steam-user-infos-right-view a {
color: #D2E885;
background: linear-gradient(to bottom, #a4d007 5%, #536904 95%);
border-radius: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
font-size: 0.9em;
font-family: 'Motiva Sans', sans-serif;
}
.steam-user-infos-right-view a:hover {
color: rgb(250, 250, 250);
}

BIN
public/img/genbg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
public/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

21
public/index.php Normal file
View File

@ -0,0 +1,21 @@
<?php
/*
Asatru PHP (dnyAsatruPHP) developed by Daniel Brendel
(C) 2019 - 2022 by Daniel Brendel
Version: 1.0
Contact: dbrendel1988<at>gmail<dot>com
GitHub: https://github.com/danielbrendel/
Released under the MIT license
*/
//If composer is installed then utilize its autoloader
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
//Include the framework bootstrap script in order to process the application
require_once __DIR__ . '/../vendor/danielbrendel/asatru-php-framework/src/bootstrap.php';

1
public/js/app.js Normal file

File diff suppressed because one or more lines are too long

2
public/js/fontawesome.js Normal file
View File

@ -0,0 +1,2 @@
window.FontAwesomeKitConfig = {"asyncLoading":{"enabled":true},"autoA11y":{"enabled":true},"baseUrl":"https://kit-free.fontawesome.com","license":"free","method":"css","minify":{"enabled":true},"v4shim":{"enabled":false},"version":"latest"};
!function(){!function(){if(!(void 0===window.Element||"classList"in document.documentElement)){var e,t,n,i=Array.prototype,o=i.push,a=i.splice,s=i.join;r.prototype={add:function(e){this.contains(e)||(o.call(this,e),this.el.className=this.toString())},contains:function(e){return-1!=this.el.className.indexOf(e)},item:function(e){return this[e]||null},remove:function(e){if(this.contains(e)){for(var t=0;t<this.length&&this[t]!=e;t++);a.call(this,t,1),this.el.className=this.toString()}},toString:function(){return s.call(this," ")},toggle:function(e){return this.contains(e)?this.remove(e):this.add(e),this.contains(e)}},window.DOMTokenList=r,e=Element.prototype,t="classList",n=function(){return new r(this)},Object.defineProperty?Object.defineProperty(e,t,{get:n}):e.__defineGetter__(t,n)}function r(e){for(var t=(this.el=e).className.replace(/^\s+|\s+$/g,"").split(/\s+/),n=0;n<t.length;n++)o.call(this,t[n])}}();function f(e){var t,n,i,o;prefixesArray=e||["fa"],prefixesSelectorString="."+Array.prototype.join.call(e,",."),t=document.querySelectorAll(prefixesSelectorString),Array.prototype.forEach.call(t,function(e){n=e.getAttribute("title"),e.setAttribute("aria-hidden","true"),i=!e.nextElementSibling||!e.nextElementSibling.classList.contains("sr-only"),n&&i&&((o=document.createElement("span")).innerHTML=n,o.classList.add("sr-only"),e.parentNode.insertBefore(o,e.nextSibling))})}var e,t,u=function(e){var t=document.createElement("link");t.href=e,t.media="all",t.rel="stylesheet",document.getElementsByTagName("head")[0].appendChild(t)},m=function(e){!function(e,t,n){var i,o=window.document,a=o.createElement("link");if(t)i=t;else{var s=(o.body||o.getElementsByTagName("head")[0]).childNodes;i=s[s.length-1]}var r=o.styleSheets;a.rel="stylesheet",a.href=e,a.media="only x",function e(t){if(o.body)return t();setTimeout(function(){e(t)})}(function(){i.parentNode.insertBefore(a,t?i:i.nextSibling)});var l=function(e){for(var t=a.href,n=r.length;n--;)if(r[n].href===t)return e();setTimeout(function(){l(e)})};function c(){a.addEventListener&&a.removeEventListener("load",c),a.media=n||"all"}a.addEventListener&&a.addEventListener("load",c),(a.onloadcssdefined=l)(c)}(e)},n=function(e,t){var n=t&&void 0!==t.autoFetchSvg?t.autoFetchSvg:void 0,i=t&&void 0!==t.async?t.async:void 0,o=t&&void 0!==t.autoA11y?t.autoA11y:void 0,a=document.createElement("script"),s=document.scripts[0];a.src=e,void 0!==o&&a.setAttribute("data-auto-a11y",o?"true":"false"),n&&(a.setAttributeNode(document.createAttribute("data-auto-fetch-svg")),a.setAttribute("data-fetch-svg-from",t.fetchSvgFrom)),i&&a.setAttributeNode(document.createAttribute("defer")),s.parentNode.appendChild(a)};function h(e,t){var n=t&&t.shim?e.license+"-v4-shims":e.license,i=t&&t.minify?".min":"";return e.baseUrl+"/releases/"+("latest"===e.version?"latest":"v".concat(e.version))+"/"+e.method+"/"+n+i+"."+e.method}try{if(window.FontAwesomeKitConfig){var i=window.FontAwesomeKitConfig;"js"===i.method&&(t={async:(e=i).asyncLoading.enabled,autoA11y:e.autoA11y.enabled},"pro"===e.license&&(t.autoFetchSvg=!0,t.fetchSvgFrom=e.baseUrl+"/releases/"+("latest"===e.version?"latest":"v".concat(e.version))+"/svgs"),e.v4shim.enabled&&n(h(e,{shim:!0,minify:e.minify.enabled})),n(h(e,{minify:e.minify.enabled}),t)),"css"===i.method&&function(e){var t,n,i,o,a,s,r,l,c=f.bind(f,["fa","fab","fas","far","fal"]);e.autoA11y.enabled&&(n=c,o=[],a=document,s=a.documentElement.doScroll,r="DOMContentLoaded",(l=(s?/^loaded|^c/:/^loaded|^i|^c/).test(a.readyState))||a.addEventListener(r,i=function(){for(a.removeEventListener(r,i),l=1;i=o.shift();)i()}),l?setTimeout(n,0):o.push(n),t=c,"undefined"!=typeof MutationObserver&&new MutationObserver(t).observe(document,{childList:!0,subtree:!0})),e.v4shim.enabled&&(e.asyncLoading.enabled?m(h(e,{shim:!0,minify:e.minify.enabled})):u(h(e,{shim:!0,minify:e.minify.enabled})));var d=h(e,{minify:e.minify.enabled});e.asyncLoading.enabled?m(d):u(d)}(i)}}catch(e){}}();

View File

@ -0,0 +1,396 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam Game/App Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_APP_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_APP_VERSION = 'v1';
/**
* Class SteamAppElem
*
* Handle custom HTML element to render Steam app/game widgets
*/
class SteamAppElem extends HTMLElement
{
storedData = {};
connectedCallback()
{
var appid = (typeof this.attributes.appid !== 'undefined') ? this.attributes.appid.value : null;
var lang = (typeof this.attributes.lang !== 'undefined') ? this.attributes.lang.value : 'english';
var playtext = (typeof this.attributes.playtext !== 'undefined') ? this.attributes.playtext.value : 'Play on Steam';
var author = (typeof this.attributes.author !== 'undefined') ? this.attributes.author.value : 'By :developer';
var onlinecount = (typeof this.attributes.onlinecount !== 'undefined') ? this.attributes.onlinecount.value : null;
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTitle = (typeof this.attributes['style-color-title'] !== 'undefined') ? this.attributes['style-color-title'].value : null;
var styleColorDescription = (typeof this.attributes['style-color-description'] !== 'undefined') ? this.attributes['style-color-description'].value : null;
var styleColorAuthor = (typeof this.attributes['style-color-author'] !== 'undefined') ? this.attributes['style-color-author'].value : null;
var styleColorOnlinecount = (typeof this.attributes['style-color-onlinecount'] !== 'undefined') ? this.attributes['style-color-onlinecount'].value : null;
var styleHideImage = (typeof this.attributes['style-hideimage'] !== 'undefined') ? parseInt(this.attributes['style-hideimage'].value) : 0;
if (appid !== null) {
this.storedData = {
appid: appid,
lang: lang,
playtext: playtext,
author: author,
onlinecount: onlinecount,
width: width,
height: height,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTitle: styleColorTitle,
styleColorDescription: styleColorDescription,
styleColorAuthor: styleColorAuthor,
styleColorOnlinecount: styleColorOnlinecount,
styleHideImage: styleHideImage
};
this.setupCard(
appid,
lang,
playtext,
author,
onlinecount,
width,
height,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTitle,
styleColorDescription,
styleColorAuthor,
styleColorOnlinecount,
styleHideImage
);
}
}
setupCard(appid, lang, playtext, author, onlinecount, width, height, styleBorder, styleShadow, styleColorBackground, styleColorTitle, styleColorDescription, styleColorAuthor, styleColorOnlinecount, styleHideImage)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (author.indexOf(':developer') !== false) {
let developers = '';
json.data.developers.forEach(function(elem, index) {
developers += elem;
if (index < json.data.developers.length - 1) {
developers += ', ';
}
});
author = author.replace(':developer', developers);
}
if (author.indexOf(':publisher') !== false) {
let publishers = '';
json.data.publishers.forEach(function(elem, index) {
publishers += elem;
if (index < json.data.publishers.length - 1) {
publishers += ', ';
}
});
author = author.replace(':publisher', publishers);
}
if (!document.getElementById('steamcards-app-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-app-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_APP_ENDPOINT + '/api/resource/query?type=css&module=app&version=' + STEAMCARDS_APP_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let onlineCountText = '';
if ((onlinecount !== null) && (json.data.online_count > 0)) {
onlineCountText = onlinecount;
onlineCountText = onlineCountText.replace(':count', self.readableCount(json.data.online_count));
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let html = `
<div class="steam-app" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-app-image" style="background-image: url('` + json.data.header_image + `'); ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + ((styleHideImage) ? 'display: none;' : '') + `"></div>
<div class="steam-app-infos">
<div class="steam-app-title">
<div class="steam-app-title-name" ` + ((styleColorTitle !== null) ? 'style="color: ' + styleColorTitle + ';"' : '') + `>` + json.data.name + `</div>
<div class="steam-app-title-count" ` + ((styleColorOnlinecount !== null) ? 'style="color: ' + styleColorOnlinecount + ';"' : '') + `>` + ((onlineCountText.length > 0) ? onlineCountText : '') + `</div>
</div>
<div class="steam-app-description" ` + ((styleColorDescription !== null) ? 'style="color: ' + styleColorDescription + ';"' : '') + `>
` + json.data.short_description + `
</div>
<div class="steam-app-footer">
<div class="steam-app-footer-author" ` + ((styleColorAuthor !== null) ? 'style="color: ' + styleColorAuthor + ';"' : '') + `>
` + author + `
</div>
<div class="steam-app-footer-button">
<a href="https://store.steampowered.com/app/` + json.appid + `">` + playtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_APP_ENDPOINT + '/api/query/app?appid=' + appid + '&lang=' + lang, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
changeLang(lang, playtext, author, onlinecount)
{
this.storedData.lang = lang;
this.storedData.playtext = playtext;
this.storedData.author = author;
this.storedData.onlinecount = onlinecount;
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
setImageVisibility(visibility)
{
this.storedData.styleHideImage = !visibility;
this.setupCard(
this.storedData.appid,
this.storedData.lang,
this.storedData.playtext,
this.storedData.author,
this.storedData.onlinecount,
this.storedData.width,
this.storedData.height,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTitle,
this.storedData.styleColorDescription,
this.storedData.styleColorAuthor,
this.storedData.styleColorOnlinecount,
this.storedData.styleHideImage
);
}
readableCount(count)
{
const COUNT_MILLION = 1000000;
const COUNT_HUNDREDTHOUSAND = 100000;
const COUNT_TENTHOUSAND = 10000;
const COUNT_THOUSAND = 1000;
if (count >= COUNT_MILLION) {
return (Math.round(count / COUNT_MILLION, 1)).toString() + 'M';
} else if ((count < COUNT_MILLION) && (count >= COUNT_HUNDREDTHOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else if ((count < COUNT_HUNDREDTHOUSAND) && (count >= COUNT_TENTHOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else if ((count < COUNT_TENTHOUSAND) && (count >= COUNT_THOUSAND)) {
return (Math.round(count / COUNT_THOUSAND, 1)).toString() + 'K';
} else {
return count.toString();
}
}
}
window.customElements.define('steam-app', SteamAppElem);
/**
* Class SteamApp
*
* Dynamically create a Steam game/app card via JavaScript
*/
class SteamApp
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var appid = (typeof config.appid !== 'undefined') ? config.appid : null;
var lang = (typeof config.lang !== 'undefined') ? config.lang : 'english';
var onlinecount = (typeof config.onlinecount !== 'undefined') ? config.onlinecount : null;
var playtext = (typeof config.playtext !== 'undefined') ? config.playtext : 'Play on Steam';
var author = (typeof config.author !== 'undefined') ? config.author : 'By :developer';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTitle = null;
var styleColorDescription = null;
var styleColorAuthor = null;
var styleColorOnlinecount = null;
var styleHideImage = 0;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTitle = (typeof config.style.colorTitle !== 'undefined') ? config.style.colorTitle : null;
styleColorDescription = (typeof config.style.colorDescription !== 'undefined') ? config.style.colorDescription : null;
styleColorAuthor = (typeof config.style.colorAuthor !== 'undefined') ? config.style.colorAuthor : null;
styleColorOnlinecount = (typeof config.style.colorOnlinecount !== 'undefined') ? config.style.colorOnlinecount : null;
styleHideImage = (typeof config.style.hideimage !== 'undefined') ? config.style.hideimage : 0;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
if (typeof styleHideImage === 'boolean') {
styleHideImage = (styleHideImage) ? 1 : 0;
}
this.elem = document.createElement('steam-app');
this.elem.setAttribute('appid', appid);
this.elem.setAttribute('lang', lang);
this.elem.setAttribute('playtext', playtext);
this.elem.setAttribute('author', author);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-title', styleColorTitle);
this.elem.setAttribute('style-color-description', styleColorDescription);
this.elem.setAttribute('style-color-author', styleColorAuthor);
this.elem.setAttribute('style-color-onlinecount', styleColorOnlinecount);
this.elem.setAttribute('style-hideimage', styleHideImage);
if (onlinecount !== null) {
this.elem.setAttribute('onlinecount', onlinecount);
}
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(lang, playtext, author, onlinecount)
{
this.elem.changeLang(lang, playtext, author, onlinecount);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

View File

@ -0,0 +1,377 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam Server Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_SERVER_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_SERVER_VERSION = 'v1';
/**
* Class SteamServerElem
*
* Handle custom HTML element to render Steam server widgets
*/
class SteamServerElem extends HTMLElement
{
storedData = {};
oldHeader = '';
connectedCallback()
{
var addr = (typeof this.attributes.addr !== 'undefined') ? this.attributes.addr.value : null;
var header = (typeof this.attributes.header !== 'undefined') ? this.attributes.header.value : '';
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var bots = (typeof this.attributes.bots !== 'undefined') ? this.attributes.bots.value : ':count bots';
var secure_yes = (typeof this.attributes['secure-yes'] !== 'undefined') ? this.attributes['secure-yes'].value : 'secure';
var secure_no = (typeof this.attributes['secure-no'] !== 'undefined') ? this.attributes['secure-no'].value : 'insecure';
var hosting_dedicated = (typeof this.attributes['hosting-dedicated'] !== 'undefined') ? this.attributes['hosting-dedicated'].value : 'dedicated';
var hosting_listen = (typeof this.attributes['hosting-listen'] !== 'undefined') ? this.attributes['hosting-listen'].value : 'listen';
var playtext = (typeof this.attributes.playtext !== 'undefined') ? this.attributes.playtext.value : 'Join';
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTextBright = (typeof this.attributes['style-color-text-bright'] !== 'undefined') ? this.attributes['style-color-text-bright'].value : null;
var styleColorTextDark = (typeof this.attributes['style-color-text-dark'] !== 'undefined') ? this.attributes['style-color-text-dark'].value : null;
if (addr !== null) {
this.storedData = {
addr: addr,
header: header,
width: width,
height: height,
bots: bots,
secure_yes: secure_yes,
secure_no: secure_no,
hosting_dedicated: hosting_dedicated,
hosting_listen: hosting_listen,
playtext: playtext,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTextBright,
styleColorTextDark
};
this.setupCard(
addr,
header,
width,
height,
bots,
secure_yes,
secure_no,
hosting_dedicated,
hosting_listen,
playtext,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTextBright,
styleColorTextDark
);
}
}
setupCard(addr, header, width, height, bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext, styleBorder, styleShadow, styleColorBackground, styleColorTextBright, styleColorTextDark)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamcards-server-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-server-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_SERVER_ENDPOINT + '/api/resource/query?type=css&module=server&version=' + STEAMCARDS_SERVER_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let bgimage = '';
if (header !== '') {
bgimage = 'background-image: url(\'' + header + '\');';
}
bots = bots.replace(':count', json.data.bots);
let security = '';
let seccol = '';
if (json.data.secure) {
security = secure_yes;
seccol = 'steam-server-gameinfo-item-green';
} else {
security = secure_no;
seccol = 'steam-server-gameinfo-item-red';
}
let hosting = '';
if (json.data.dedicated) {
hosting = hosting_dedicated;
} else {
hosting = hosting_listen;
}
let html = `
<div class="steam-server" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-server-image" style="` + bgimage + ` ` + ((header == '') ? 'display: none;' : '') + ` ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + `"></div>
<div class="steam-server-infos">
<div class="steam-server-title">
<div class="steam-server-title-left">
<div class="steam-server-title-left-addr" ` + ((styleColorTextBright !== null) ? 'style="color: ' + styleColorTextBright + ';"' : '') + `>` + json.data.addr + `</div>
<div class="steam-server-title-left-name" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>`+ json.data.name + `</div>
</div>
<div class="steam-server-title-right">
<div class="steam-server-title-right-count" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + json.data.players + `/` + json.data.max_players + `</div>
<div class="steam-server-title-right-bots" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + bots + `</div>
</div>
</div>
<div class="steam-server-footer">
<div class="steam-server-gameinfo" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>
<span class="steam-server-gameinfo-item">` + json.data.product + `</span>
|
<span class="steam-server-gameinfo-item">`+ json.data.map + `</span>
|
<span class="steam-server-gameinfo-item ` + seccol + `">` + security + `</span>
|
<span class="steam-server-gameinfo-item">` + hosting + `</span>
</div>
<div class="steam-server-action">
<a href="steam://connect/` + json.data.addr + `">` + playtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_SERVER_ENDPOINT + '/api/query/server?addr=' + addr, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext)
{
this.storedData.bots = bots;
this.storedData.secure_yes = secure_yes;
this.storedData.secure_no = secure_no;
this.storedData.hosting_dedicated = hosting_dedicated;
this.storedData.hosting_listen = hosting_listen;
this.storedData.playtext = playtext;
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
setImageVisibility(visibility)
{
if (visibility) {
this.storedData.header = this.oldHeader;
} else {
if (this.storedData.header != '') {
this.oldHeader = this.storedData.header;
}
this.storedData.header = '';
}
this.setupCard(
this.storedData.addr,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.bots,
this.storedData.secure_yes,
this.storedData.secure_no,
this.storedData.hosting_dedicated,
this.storedData.hosting_listen,
this.storedData.playtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
}
window.customElements.define('steam-server', SteamServerElem);
/**
* Class SteamServer
*
* Dynamically create a Steam server card via JavaScript
*/
class SteamServer
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var addr = (typeof config.addr !== 'undefined') ? config.addr : null;
var header = (typeof config.header !== 'undefined') ? config.header : '';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var bots = (typeof config.bots !== 'undefined') ? config.bots : ':count bots';
var secure_yes = (typeof config.secure_yes !== 'undefined') ? config.secure_yes : 'secure';
var secure_no = (typeof config.secure_no !== 'undefined') ? config.secure_no : 'insecure';
var hosting_dedicated = (typeof config.hosting_dedicated !== 'undefined') ? config.hosting_dedicated : 'dedicated';
var hosting_listen = (typeof config.hosting_listen !== 'undefined') ? config.hosting_listen : 'listen';
var playtext = (typeof config.playtext !== 'undefined') ? config.playtext : 'Join';
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTextBright = null;
var styleColorTextDark = null;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTextBright = (typeof config.style.colorTextBright !== 'undefined') ? config.style.colorTextBright : null;
styleColorTextDark = (typeof config.style.colorTextDark !== 'undefined') ? config.style.colorTextDark : null;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-server');
this.elem.setAttribute('addr', addr);
this.elem.setAttribute('header', header);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-text-bright', styleColorTextBright);
this.elem.setAttribute('style-color-text-dark', styleColorTextDark);
this.elem.setAttribute('bots', bots);
this.elem.setAttribute('secure-yes', secure_yes);
this.elem.setAttribute('secure-no', secure_no);
this.elem.setAttribute('hosting-dedicated', hosting_dedicated);
this.elem.setAttribute('hosting-listen', hosting_listen);
this.elem.setAttribute('playtext', playtext);
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext)
{
this.elem.changeLang(bots, secure_yes, secure_no, hosting_dedicated, hosting_listen, playtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

View File

@ -0,0 +1,344 @@
/**
* SteamCards - Steam Cards for your website
*
* Module: Steam User Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMCARDS_USER_ENDPOINT = 'http://localhost:8000';
const STEAMCARDS_USER_VERSION = 'v1';
/**
* Class SteamUserElem
*
* Handle custom HTML element to render Steam user widgets
*/
class SteamUserElem extends HTMLElement
{
storedData = {};
oldHeader = '';
connectedCallback()
{
var steamid = (typeof this.attributes.steamid !== 'undefined') ? this.attributes.steamid.value : null;
var header = (typeof this.attributes.header !== 'undefined') ? this.attributes.header.value : '';
var width = (typeof this.attributes.width !== 'undefined') ? this.attributes.width.value : null;
var height = (typeof this.attributes.height !== 'undefined') ? this.attributes.height.value : null;
var online_yes = (typeof this.attributes['online-yes'] !== 'undefined') ? this.attributes['online-yes'].value : 'online';
var online_no = (typeof this.attributes['online-no'] !== 'undefined') ? this.attributes['online-no'].value : 'offline';
var member_since = (typeof this.attributes['member-since'] !== 'undefined') ? this.attributes['member-since'].value : 'Member since: :year-:month-:day';
var viewtext = (typeof this.attributes.viewtext !== 'undefined') ? this.attributes.viewtext.value : 'View';
var styleBorder = (typeof this.attributes['style-border'] !== 'undefined') ? this.attributes['style-border'].value : null;
var styleShadow = (typeof this.attributes['style-shadow'] !== 'undefined') ? parseInt(this.attributes['style-shadow'].value) : 1;
var styleColorBackground = (typeof this.attributes['style-color-background'] !== 'undefined') ? this.attributes['style-color-background'].value : null;
var styleColorTextBright = (typeof this.attributes['style-color-text-bright'] !== 'undefined') ? this.attributes['style-color-text-bright'].value : null;
var styleColorTextDark = (typeof this.attributes['style-color-text-dark'] !== 'undefined') ? this.attributes['style-color-text-dark'].value : null;
if (steamid !== null) {
this.storedData = {
steamid: steamid,
header: header,
width: width,
height: height,
online_yes: online_yes,
online_no: online_no,
member_since: member_since,
viewtext: viewtext,
styleBorder: styleBorder,
styleShadow: styleShadow,
styleColorBackground: styleColorBackground,
styleColorTextBright,
styleColorTextDark
};
this.setupCard(
steamid,
header,
width,
height,
online_yes,
online_no,
member_since,
viewtext,
styleBorder,
styleShadow,
styleColorBackground,
styleColorTextBright,
styleColorTextDark
);
}
}
setupCard(steamid, header, width, height, online_yes, online_no, member_since, viewtext, styleBorder, styleShadow, styleColorBackground, styleColorTextBright, styleColorTextDark)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamcards-user-styles')) {
let link = document.createElement('link');
link.id = 'steamcards-user-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMCARDS_USER_ENDPOINT + '/api/resource/query?type=css&module=user&version=' + STEAMCARDS_USER_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let cardImageStyle = '';
let cardStyle = '';
if ((width !== null) || (styleBorder !== null) || (styleShadow !== true) || (styleColorBackground !== null)) {
let widthCode = '';
if (width !== null) {
widthCode = 'max-width: ' + width + 'px;';
}
let borderCode = '';
if (styleBorder !== null) {
if (styleBorder === 'max') {
borderCode = 'border-radius: 25px;';
cardImageStyle = 'border-top-left-radius: 25px; border-top-right-radius: 25px;';
} else if (styleBorder === 'small') {
borderCode = 'border-radius: 4px;';
cardImageStyle = 'border-top-left-radius: 4px; border-top-right-radius: 4px;';
} else if (styleBorder === 'none') {
borderCode = 'border-radius: unset;';
cardImageStyle = 'border-top-left-radius: unset; border-top-right-radius: unset;';
}
}
let shadowCode = '';
if (!styleShadow) {
shadowCode = 'box-shadow: unset;';
}
let bgColor = '';
if (styleColorBackground !== null) {
bgColor = 'background-color: ' + styleColorBackground + ';';
}
cardStyle = 'style="' + widthCode + borderCode + shadowCode + bgColor + '"';
}
let bgimage = '';
if (header !== '') {
bgimage = 'background-image: url(\'' + header + '\');';
}
let onstatus = '';
let oncolor = '';
if (json.data.personastate) {
onstatus = online_yes;
oncolor = 'steam-user-infos-right-online-green';
} else {
onstatus = online_no;
oncolor = '';
}
let regdate = new Date(json.data.timecreated * 1000);
member_since = member_since.replace(':year', regdate.getFullYear());
member_since = member_since.replace(':month', regdate.getMonth() + 1);
member_since = member_since.replace(':day', regdate.getDate());
let html = `
<div class="steam-user" ` + ((cardStyle.length > 0) ? cardStyle: '') + `>
<div class="steam-user-image" style="` + bgimage + ` ` + ((header == '') ? 'display: none;' : '') + ` ` + ((height !== null) ? 'height: ' + height + 'px;' : '') + ((cardImageStyle.length > 0) ? cardImageStyle : '') + `"></div>
<div class="steam-user-infos">
<div class="steam-user-infos-left">
<div class="steam-user-infos-left-avatar"><img src="` + json.data.avatarfull + `" alt="Avatar"/></div>
<div class="steam-user-infos-left-text">
<div class="steam-user-infos-left-text-name" ` + ((styleColorTextBright !== null) ? 'style="color: ' + styleColorTextBright + ';"' : '') + `>` + json.data.personaname + `</div>
<div class="steam-user-infos-left-text-since" ` + ((styleColorTextDark !== null) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + member_since + `</div>
</div>
</div>
<div class="steam-user-infos-right">
<div class="steam-user-infos-right-online ` + ((json.data.personastate) ? oncolor : '') + `" ` + (((styleColorTextDark !== null) && (json.data.personastate)) ? 'style="color: ' + styleColorTextDark + ';"' : '') + `>` + onstatus + `</div>
<div class="steam-user-infos-right-view">
<a href="` + json.data.profileurl + `">` + viewtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMCARDS_USER_ENDPOINT + '/api/query/user?steamid=' + steamid, true);
req.send();
}
updateCard()
{
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
changeLang(online_yes, online_no, member_since, viewtext)
{
this.storedData.online_yes = online_yes;
this.storedData.online_no = online_no;
this.storedData.member_since = member_since;
this.storedData.viewtext = viewtext;
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
setImageVisibility(visibility)
{
if (visibility) {
this.storedData.header = this.oldHeader;
} else {
if (this.storedData.header != '') {
this.oldHeader = this.storedData.header;
}
this.storedData.header = '';
}
this.setupCard(
this.storedData.steamid,
this.storedData.header,
this.storedData.width,
this.storedData.height,
this.storedData.online_yes,
this.storedData.online_no,
this.storedData.member_since,
this.storedData.viewtext,
this.storedData.styleBorder,
this.storedData.styleShadow,
this.storedData.styleColorBackground,
this.storedData.styleColorTextBright,
this.storedData.styleColorTextDark,
);
}
}
window.customElements.define('steam-user', SteamUserElem);
/**
* Class SteamUser
*
* Dynamically create a Steam user card via JavaScript
*/
class SteamUser
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var steamid = (typeof config.steamid !== 'undefined') ? config.steamid : null;
var header = (typeof config.header !== 'undefined') ? config.header : '';
var width = (typeof config.width !== 'undefined') ? config.width : null;
var height = (typeof config.height !== 'undefined') ? config.height : null;
var online_yes = (typeof config.online_yes !== 'undefined') ? config.online_yes : 'online';
var online_no = (typeof config.online_no !== 'undefined') ? config.online_no : 'offline';
var member_since = (typeof config.member_since !== 'undefined') ? config.member_since : 'Member since: :year-:month-:day';
var viewtext = (typeof config.viewtext !== 'undefined') ? config.viewtext : 'View';
var styleBorder = null;
var styleShadow = 1;
var styleColorBackground = null;
var styleColorTextBright = null;
var styleColorTextDark = null;
if (typeof config.style !== 'undefined') {
styleBorder = (typeof config.style.border !== 'undefined') ? config.style.border : null;
styleShadow = (typeof config.style.shadow !== 'undefined') ? config.style.shadow : 1;
styleColorBackground = (typeof config.style.colorBackground !== 'undefined') ? config.style.colorBackground : null;
styleColorTextBright = (typeof config.style.colorTextBright !== 'undefined') ? config.style.colorTextBright : null;
styleColorTextDark = (typeof config.style.colorTextDark !== 'undefined') ? config.style.colorTextDark : null;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-user');
this.elem.setAttribute('steamid', steamid);
this.elem.setAttribute('header', header);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
this.elem.setAttribute('style-color-background', styleColorBackground);
this.elem.setAttribute('style-color-text-bright', styleColorTextBright);
this.elem.setAttribute('style-color-text-dark', styleColorTextDark);
this.elem.setAttribute('online-yes', online_yes);
this.elem.setAttribute('online-no', online_no);
this.elem.setAttribute('member-since', member_since);
this.elem.setAttribute('viewtext', viewtext);
if (width !== null) {
this.elem.setAttribute('width', width);
}
if (height !== null) {
this.elem.setAttribute('height', height);
}
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateCard()
{
this.elem.updateCard();
}
changeLang(online_yes, online_no, member_since, viewtext)
{
this.elem.changeLang(online_yes, online_no, member_since, viewtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

11944
public/js/vue.js Normal file

File diff suppressed because it is too large Load Diff

6
public/js/vue.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
public/robots.txt Normal file
View File

@ -0,0 +1,2 @@
User-agent: *
Disallow:

24
webpack.config.js Normal file
View File

@ -0,0 +1,24 @@
const path = require('path');
module.exports = {
entry: './app/resources/js/app.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'public/js'),
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
},
],
},
};