New widget: Steam Workshop

This commit is contained in:
Daniel Brendel
2022-09-25 12:35:24 +02:00
parent a54c495622
commit f52cb919cf
18 changed files with 1075 additions and 700 deletions

View File

@ -13,7 +13,7 @@ SteamWidgets offers the possibility to comfortably render Steam related widgets
document with as less effort as possible. document with as less effort as possible.
## Current featured widgets ## Current featured widgets
- Steam App Widget: Renders a widget of a Steam app/game - Steam App Widget: Renders widgets of a Steam app/game
- Steam Server Widget: Renders a widget of a Steam game server - Steam Server Widget: Renders widgets of a Steam game server
- Steam User Widget: Renders a widget of a Steam user - Steam User Widget: Renders widgets of a Steam user
- Steam Workshop Widget: Renders widgets of a Steam workshop item

View File

@ -17,10 +17,10 @@
return [ return [
array('/', 'GET', 'index@index'), array('/', 'GET', 'index@index'),
array('/generator', 'GET', 'index@generator'),
array('/api/query/app', 'GET', 'api@queryAppInfo'), array('/api/query/app', 'GET', 'api@queryAppInfo'),
array('/api/query/server', 'GET', 'api@queryServerInfo'), array('/api/query/server', 'GET', 'api@queryServerInfo'),
array('/api/query/user', 'GET', 'api@queryUserInfo'), array('/api/query/user', 'GET', 'api@queryUserInfo'),
array('/api/query/workshop', 'GET', 'api@queryWorkshopInfo'),
array('/api/resource/query', 'GET', 'api@queryResource'), array('/api/resource/query', 'GET', 'api@queryResource'),
array('/stats/{pw}', 'GET', 'stats@index'), array('/stats/{pw}', 'GET', 'stats@index'),
array('/stats/query/{pw}', 'ANY', 'stats@query'), array('/stats/query/{pw}', 'ANY', 'stats@query'),

View File

@ -81,6 +81,28 @@ class ApiController extends BaseController {
} }
} }
/**
* Query Steam workshop data
*
* @param Asatru\Controller\ControllerArg $request
* @return Asatru\View\JsonHandler
*/
public function queryWorkshopInfo($request)
{
try {
$itemid = $request->params()->query('itemid', null);
$data = SteamWorkshop::querySteamData($itemid);
//Save hit
HitsModel::addHit(HitsModel::HITTYPE_MODULE_WORKSHOP);
return json(array('code' => 200, 'itemid' => $itemid, 'data' => $data));
} catch (\Exception $e) {
return json(array('code' => 500, 'msg' => $e->getMessage()));
}
}
/** /**
* Query JavaScript or CSS resource for component * Query JavaScript or CSS resource for component
* *

View File

@ -27,16 +27,4 @@ class IndexController extends BaseController {
//Generate and return a view by using the helper //Generate and return a view by using the helper
return parent::view(['content', 'index']); 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

@ -10,6 +10,7 @@ class HitsModel extends \Asatru\Database\Model
const HITTYPE_MODULE_APP = 'mod_app'; const HITTYPE_MODULE_APP = 'mod_app';
const HITTYPE_MODULE_SERVER = 'mod_server'; const HITTYPE_MODULE_SERVER = 'mod_server';
const HITTYPE_MODULE_USER = 'mod_user'; const HITTYPE_MODULE_USER = 'mod_user';
const HITTYPE_MODULE_WORKSHOP = 'mod_workshop';
/** /**
* Validate hit type * Validate hit type
@ -21,7 +22,7 @@ class HitsModel extends \Asatru\Database\Model
public static function validateHitType($type) public static function validateHitType($type)
{ {
try { try {
$types = [self::HITTYPE_MODULE_APP, self::HITTYPE_MODULE_SERVER, self::HITTYPE_MODULE_USER]; $types = [self::HITTYPE_MODULE_APP, self::HITTYPE_MODULE_SERVER, self::HITTYPE_MODULE_USER, self::HITTYPE_MODULE_WORKSHOP];
if (!in_array($type, $types)) { if (!in_array($type, $types)) {
throw new Exception('Invalid hit type: ' . $type); throw new Exception('Invalid hit type: ' . $type);

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* Class SteamAppModel * Class SteamApp
* *
* Responsible for querying Steam game/app data * Responsible for querying Steam game/app data
*/ */

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* Class SteamServerModel * Class SteamServer
* *
* Responsible for querying Steam server data * Responsible for querying Steam server data
*/ */

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* Class SteamUserModel * Class SteamUser
* *
* Responsible for querying Steam user data * Responsible for querying Steam user data
*/ */

View File

@ -0,0 +1,53 @@
<?php
/**
* Class SteamWorkshop
*
* Responsible for querying Steam Workshop data
*/
class SteamWorkshop
{
const STEAM_ENDPOINT = 'https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/';
/**
* Query item data from Steam Workshop item
*
* @param $appid
* @param $lang
* @return mixed
* @throws \Exception
*/
public static function querySteamData($itemid)
{
$handle = curl_init(self::STEAM_ENDPOINT);
curl_setopt($handle, CURLOPT_HEADER, false);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_POSTFIELDS, "itemcount=1&publishedfileids[0]={$itemid}");
$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) && (isset($obj->response->resultcount)) && ($obj->response->resultcount == 1)) {
$obj->response->publishedfiledetails[0]->creator_data = null;
try {
$obj->response->publishedfiledetails[0]->creator_data = SteamUser::querySteamData(env('STEAM_API_KEY'), $obj->response->publishedfiledetails[0]->creator);
} catch (\Exception $e) {
}
return $obj->response->publishedfiledetails[0];
}
throw new \Exception('Invalid data response');
}
}

View File

@ -0,0 +1,133 @@
.steam-workshop {
position: relative;
min-width: 360px;
max-width: 555px;
height: 205px;
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-workshop-preview {
position: relative;
display: inline-block;
min-width: 205px;
height: 205px;
background-repeat: no-repeat;
background-size: 100% 100%;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
}
.steam-workshop-info {
position: relative;
display: inline-block;
width: 55%;
margin-left: 20px;
top: -20px;
}
.steam-workshop-info-title {
margin-bottom: 10px;
color: rgb(220, 220, 220);
font-size: 1.1em;
font-family: Verdana, Arial, sans-serif;
}
.steam-workshop-info-description {
margin-bottom: 10px;
color: rgb(150, 150, 150);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
}
.steam-workshop-info-stats {
margin-bottom: 12px;
}
.steam-workshop-info-stats-item {
}
.steam-workshop-info-stats-item-count {
display: inline-block;
min-width: 50px;
color: rgb(59, 135, 185);
}
.steam-workshop-info-stats-item-label {
display: inline-block;
text-transform: uppercase;
color: rgb(100, 100, 100);
}
.steam-workshop-info-footer {
}
.steam-workshop-info-footer-author {
display: inline-block;
width: 69%;
}
.steam-workshop-info-footer-author a {
color: rgb(50, 115, 220);
}
.steam-workshop-info-footer-author a:hover {
color: rgb(50, 115, 220);
text-decoration: underline;
}
.steam-workshop-info-footer-action {
display: inline-block;
}
.steam-workshop-info-footer-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-workshop-info-footer-action a:hover {
color: rgb(250, 250, 250);
}
@media screen and (max-width: 465px) {
.steam-workshop {
min-width: unset;
width: 350px;
min-height: 205px;
height: unset;
}
.steam-workshop-preview {
min-width: unset;
width: 350px;
height: 350px;
border-top-right-radius: 25px;
border-bottom-left-radius: unset;
}
.steam-workshop-info {
width: 100%;
height: 195px;
top: unset;
}
.steam-workshop-info-title {
margin-top: 5px;
}
.steam-workshop-info-footer-author {
width: 64%;
}
}

View File

@ -0,0 +1,285 @@
/**
* SteamWidgets - Steam Widgets for your website
*
* Module: Steam Workshop Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMWIDGETS_WORKSHOP_ENDPOINT = 'http://localhost:8000';
const STEAMWIDGETS_WORKSHOP_VERSION = 'v1';
/**
* Class SteamWorkshopElem
*
* Handle custom HTML element to render Steam workshop widgets
*/
class SteamWorkshopElem extends HTMLElement
{
DESCRIPTION_MAX_LEN = 40;
storedData = {};
oldHeader = '';
connectedCallback()
{
var itemid = (typeof this.attributes.itemid !== 'undefined') ? this.attributes.itemid.value : null;
var views = (typeof this.attributes.views !== 'undefined') ? this.attributes.views.value : 'Views';
var subscriptions = (typeof this.attributes.subscriptions !== 'undefined') ? this.attributes.subscriptions.value : 'Subscriptions';
var favorites = (typeof this.attributes.favorites !== 'undefined') ? this.attributes.favorites.value : 'Favorites';
var author = (typeof this.attributes.author !== 'undefined') ? this.attributes.author.value : 'By :creator';
var viewtext = (typeof this.attributes.viewtext !== 'undefined') ? this.attributes.viewtext.value : 'View item';
var showImage = (typeof this.attributes['show-image'] !== 'undefined') ? parseInt(this.attributes['show-image'].value) : 1;
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;
if (itemid !== null) {
this.storedData = {
itemid: itemid,
views: views,
subscriptions: subscriptions,
favorites: favorites,
author: author,
viewtext: viewtext,
showImage: showImage,
styleBorder: styleBorder,
styleShadow: styleShadow
};
this.setupWidget(
itemid,
views,
subscriptions,
favorites,
author,
viewtext,
showImage,
styleBorder,
styleShadow
);
}
}
setupWidget(itemid, views, subscriptions, favorites, author, viewtext, showImage, styleBorder, styleShadow)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamwidgets-workshop-styles')) {
let link = document.createElement('link');
link.id = 'steamwidgets-workshop-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMWIDGETS_WORKSHOP_ENDPOINT + '/api/resource/query?type=css&module=workshop&version=' + STEAMWIDGETS_WORKSHOP_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let description = json.data.description;
if (description.length >= self.DESCRIPTION_MAX_LEN) {
description = description.substr(0, self.DESCRIPTION_MAX_LEN - 3) + '...';
}
author = author.replace(':creator', json.data.creator_data.personaname);
let html = `
<div class="steam-workshop" ` + ((!styleShadow) ? 'style="box-shadow: unset;"' : '') + `>
<div class="steam-workshop-preview" style="background-image: url('` + json.data.preview_url + `'); ` + ((!showImage) ? 'display: none;' : '') + `"></div>
<div class="steam-workshop-info" ` + ((!showImage) ? 'style="top: 13px; width: 100%;"' : '') + `>
<div class="steam-workshop-info-title">` + json.data.title + `</div>
<div class="steam-workshop-info-description">` + description + `</div>
<div class="steam-workshop-info-stats">
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.views) + `</div>
<div class="steam-workshop-info-stats-item-label">` + views + `</div>
</div>
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.subscriptions) + `</div>
<div class="steam-workshop-info-stats-item-label">`+ subscriptions + `</div>
</div>
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.favorited) + `</div>
<div class="steam-workshop-info-stats-item-label">`+ favorites + `</div>
</div>
</div>
<div class="steam-workshop-info-footer">
<div class="steam-workshop-info-footer-author"><a href="` + json.data.creator_data.profileurl + `">` + author + `</a></div>
<div class="steam-workshop-info-footer-action">
<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=` + json.data.publishedfileid + `">` + viewtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMWIDGETS_WORKSHOP_ENDPOINT + '/api/query/workshop?itemid=' + itemid, true);
req.send();
}
updateWidget()
{
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
changeLang(views, subscriptions, favorites, author, viewtext)
{
this.storedData.views = views;
this.storedData.subscriptions = subscriptions;
this.storedData.favorites = favorites;
this.storedData.author = author;
this.storedData.viewtext = viewtext;
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
setImageVisibility(visibility)
{
this.storedData.showImage = visibility;
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
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-workshop', SteamWorkshopElem);
/**
* Class SteamWorkshop
*
* Dynamically create a Steam workshop widgets via JavaScript
*/
class SteamWorkshop
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var itemid = (typeof config.itemid !== 'undefined') ? config.itemid : null;
var views = (typeof config.views !== 'undefined') ? config.views : 'Views';
var subscriptions = (typeof config.subscriptions !== 'undefined') ? config.subscriptions : 'Subscriptions';
var favorites = (typeof config.favorites !== 'undefined') ? config.favorites : 'Favorites';
var author = (typeof config.author !== 'undefined') ? config.author : 'By :creator';
var viewtext = (typeof config.viewtext !== 'undefined') ? config.viewtext : 'View item';
var showImage = (typeof config.showImage !== 'undefined') ? config.showImage : null;
if (typeof showImage === 'boolean') {
showImage = (showImage) ? 1 : 0;
}
var styleBorder = null;
var styleShadow = 1;
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;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-workshop');
this.elem.setAttribute('itemid', itemid);
this.elem.setAttribute('views', views);
this.elem.setAttribute('subscriptions', subscriptions);
this.elem.setAttribute('favorites', favorites);
this.elem.setAttribute('author', author);
this.elem.setAttribute('viewtext', viewtext);
this.elem.setAttribute('show-image', showImage);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateWidget()
{
this.elem.updateWidget();
}
changeLang(views, subscriptions, favorites, author, viewtext)
{
this.elem.changeLang(views, subscriptions, favorites, author, viewtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}

View File

@ -1,677 +0,0 @@
<!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>{{ env('APP_NAME') }} 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">Rating</label>
<div class="control">
<input type="text" class="input" id="inp-widget-app-rating" value="0"/>
</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 rating = document.getElementById('inp-widget-app-rating').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 + `" rating="` + rating + `" 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 sampleWidget = new SteamApp('#widget-sample-app', {
appid: appid,
lang: lang,
playtext: playtext,
onlinecount: onlinecount,
rating: rating,
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 sampleWidget = 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 sampleWidget = 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>

View File

@ -26,6 +26,7 @@
<li><a href="#steam-app">Steam App Widget</a></li> <li><a href="#steam-app">Steam App Widget</a></li>
<li><a href="#steam-server">Steam Server Widget</a></li> <li><a href="#steam-server">Steam Server Widget</a></li>
<li><a href="#steam-user">Steam User Widget</a></li> <li><a href="#steam-user">Steam User Widget</a></li>
<li><a href="#steam-workshop">Steam Workshop Widget</a></li>
</ul> </ul>
</p> </p>
@ -40,8 +41,8 @@
<br/> <br/>
<i>STEAM_WIDGETS_MODULE</i> can either be <b>app</b> for the Steam App widget, <b>server</b> for the Steam Server widget or <i>STEAM_WIDGETS_MODULE</i> can either be <b>app</b> for the Steam App widget, <b>server</b> for the Steam Server widget,
<b>user</b> for the Steam User widget. <b>user</b> for the Steam User widget or <b>workshop</b> for the Steam Workshop widget.
</p> </p>
@if (env('APP_SHOWNPMUSAGE', false)) @if (env('APP_SHOWNPMUSAGE', false))
@ -546,6 +547,143 @@ document.addEventListener('DOMContentLoaded', function() {
<td>Sets the widget image visibility</td> <td>Sets the widget image visibility</td>
</tr> </tr>
<tr>
<td>remove()</td>
<td>Removes the widget from the document</td>
</tr>
</tbody>
</table>
</p>
</div>
<div class="content-section">
<a name="steam-workshop"></a><br/><br/>
<h3>Steam Workshop</h3>
<p>
When referenced the required Steam Workshop module, the minimum code to render a widget is as follows:<br/>
<pre>
<code class="language-html">
&lt;steam-workshop itemid="id"&gt;&lt;/steam-workshop&gt;
</code>
</pre>
<br/><br/>
This renders the following widget:<br/>
<steam-workshop itemid="itemid"></steam-workshop>
</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>itemid</td>
<td>Specifies the item ID of the Steam Workshop item</td>
</tr>
<tr>
<td>views</td>
<td>Specifies the text of the views stats label</td>
</tr>
<tr class="tr-colored">
<td>subscriptions</td>
<td>Specifies the text of the subscriptions stats label</td>
</tr>
<tr>
<td>favorites</td>
<td>Specifies the text of the favorites stats label</td>
</tr>
<tr class="tr-colored">
<td>author</td>
<td>Specifies the author text. Use <b>:creator</b> to insert the creators Steam persona name</td>
</tr>
<tr>
<td>viewtext</td>
<td>Specifies the text of the button which can be used to go to the Workshop item page</td>
</tr>
<tr class="tr-colored">
<td>show-image / showImage</td>
<td>Specifies if the workshop item preview image shall be displayed. Defaults to true/1</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>
</tbody>
</table>
</p>
<p>
You can also dynamically create Steam Workshop widgets via JavaScript:<br/>
<pre>
<code class="language-html">
&lt;div id="workshop-widget"&gt;&lt;/div&gt;
&lt;script&gt;
document.addEventListener('DOMContentLoaded', function() {
let widget = new SteamWorkshop('#workshop-widget', {
itemid: '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 Workshop 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>updateWidget()</td>
<td>Updates the widget data and displays them</td>
</tr>
<tr>
<td>changeLang(views, subscriptions, favorites, author, viewtext)</td>
<td>Changes the language of the widget using the given information</td>
</tr>
<tr class="tr-colored">
<td>setImageVisibility(visibility)</td>
<td>Sets the widget image visibility</td>
</tr>
<tr> <tr>
<td>remove()</td> <td>remove()</td>
<td>Removes the widget from the document</td> <td>Removes the widget from the document</td>

View File

@ -22,6 +22,7 @@
<script src="{{ url('/api/resource/query') }}?type=js&module=app&version=v1"></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=server&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=user&version=v1"></script> <script src="{{ url('/api/resource/query') }}?type=js&module=user&version=v1"></script>
<script src="{{ url('/api/resource/query') }}?type=js&module=workshop&version=v1"></script>
</head> </head>
<body> <body>

View File

@ -28,6 +28,10 @@
<a class="navbar-item" href="{{ url('/#steam-user') }}" onclick="document.getElementById('burger-button').click(); return true;"> <a class="navbar-item" href="{{ url('/#steam-user') }}" onclick="document.getElementById('burger-button').click(); return true;">
Steam User Steam User
</a> </a>
<a class="navbar-item" href="{{ url('/#steam-workshop') }}" onclick="document.getElementById('burger-button').click(); return true;">
Steam Workshop
</a>
</div> </div>
<div class="navbar-end"> <div class="navbar-end">

View File

@ -16,6 +16,9 @@ del "%~dp0public\css\steamwidgets\%ver%\steam_server.css"
del "%~dp0public\js\steamwidgets\%ver%\steam_user.js" del "%~dp0public\js\steamwidgets\%ver%\steam_user.js"
del "%~dp0public\css\steamwidgets\%ver%\steam_user.css" del "%~dp0public\css\steamwidgets\%ver%\steam_user.css"
del "%~dp0public\js\steamwidgets\%ver%\steam_workshop.js"
del "%~dp0public\css\steamwidgets\%ver%\steam_workshop.css"
xcopy "%~dp0app\resources\js\steam_app.dev.js" "%~dp0public\js\steamwidgets\%ver%\" /Y xcopy "%~dp0app\resources\js\steam_app.dev.js" "%~dp0public\js\steamwidgets\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_app.dev.css" "%~dp0public\css\steamwidgets\%ver%\" /Y xcopy "%~dp0app\resources\css\steam_app.dev.css" "%~dp0public\css\steamwidgets\%ver%\" /Y
@ -25,6 +28,9 @@ xcopy "%~dp0app\resources\css\steam_server.dev.css" "%~dp0public\css\steamwidget
xcopy "%~dp0app\resources\js\steam_user.dev.js" "%~dp0public\js\steamwidgets\%ver%\" /Y xcopy "%~dp0app\resources\js\steam_user.dev.js" "%~dp0public\js\steamwidgets\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_user.dev.css" "%~dp0public\css\steamwidgets\%ver%\" /Y xcopy "%~dp0app\resources\css\steam_user.dev.css" "%~dp0public\css\steamwidgets\%ver%\" /Y
xcopy "%~dp0app\resources\js\steam_workshop.dev.js" "%~dp0public\js\steamwidgets\%ver%\" /Y
xcopy "%~dp0app\resources\css\steam_workshop.dev.css" "%~dp0public\css\steamwidgets\%ver%\" /Y
ren "%~dp0public\js\steamwidgets\%ver%\steam_app.dev.js" "steam_app.js" ren "%~dp0public\js\steamwidgets\%ver%\steam_app.dev.js" "steam_app.js"
ren "%~dp0public\css\steamwidgets\%ver%\steam_app.dev.css" "steam_app.css" ren "%~dp0public\css\steamwidgets\%ver%\steam_app.dev.css" "steam_app.css"
@ -34,6 +40,9 @@ ren "%~dp0public\css\steamwidgets\%ver%\steam_server.dev.css" "steam_server.css"
ren "%~dp0public\js\steamwidgets\%ver%\steam_user.dev.js" "steam_user.js" ren "%~dp0public\js\steamwidgets\%ver%\steam_user.dev.js" "steam_user.js"
ren "%~dp0public\css\steamwidgets\%ver%\steam_user.dev.css" "steam_user.css" ren "%~dp0public\css\steamwidgets\%ver%\steam_user.dev.css" "steam_user.css"
ren "%~dp0public\js\steamwidgets\%ver%\steam_workshop.dev.js" "steam_workshop.js"
ren "%~dp0public\css\steamwidgets\%ver%\steam_workshop.dev.css" "steam_workshop.css"
echo "Job done" echo "Job done"
pause pause

View File

@ -0,0 +1,133 @@
.steam-workshop {
position: relative;
min-width: 360px;
max-width: 555px;
height: 205px;
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-workshop-preview {
position: relative;
display: inline-block;
min-width: 205px;
height: 205px;
background-repeat: no-repeat;
background-size: 100% 100%;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
}
.steam-workshop-info {
position: relative;
display: inline-block;
width: 55%;
margin-left: 20px;
top: -20px;
}
.steam-workshop-info-title {
margin-bottom: 10px;
color: rgb(220, 220, 220);
font-size: 1.1em;
font-family: Verdana, Arial, sans-serif;
}
.steam-workshop-info-description {
margin-bottom: 10px;
color: rgb(150, 150, 150);
font-size: 0.8em;
font-family: Verdana, Arial, sans-serif;
}
.steam-workshop-info-stats {
margin-bottom: 12px;
}
.steam-workshop-info-stats-item {
}
.steam-workshop-info-stats-item-count {
display: inline-block;
min-width: 50px;
color: rgb(59, 135, 185);
}
.steam-workshop-info-stats-item-label {
display: inline-block;
text-transform: uppercase;
color: rgb(100, 100, 100);
}
.steam-workshop-info-footer {
}
.steam-workshop-info-footer-author {
display: inline-block;
width: 69%;
}
.steam-workshop-info-footer-author a {
color: rgb(50, 115, 220);
}
.steam-workshop-info-footer-author a:hover {
color: rgb(50, 115, 220);
text-decoration: underline;
}
.steam-workshop-info-footer-action {
display: inline-block;
}
.steam-workshop-info-footer-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-workshop-info-footer-action a:hover {
color: rgb(250, 250, 250);
}
@media screen and (max-width: 465px) {
.steam-workshop {
min-width: unset;
width: 350px;
min-height: 205px;
height: unset;
}
.steam-workshop-preview {
min-width: unset;
width: 350px;
height: 350px;
border-top-right-radius: 25px;
border-bottom-left-radius: unset;
}
.steam-workshop-info {
width: 100%;
height: 195px;
top: unset;
}
.steam-workshop-info-title {
margin-top: 5px;
}
.steam-workshop-info-footer-author {
width: 64%;
}
}

View File

@ -0,0 +1,285 @@
/**
* SteamWidgets - Steam Widgets for your website
*
* Module: Steam Workshop Widget
*
* Visit: https://github.com/danielbrendel
*/
const STEAMWIDGETS_WORKSHOP_ENDPOINT = 'http://localhost:8000';
const STEAMWIDGETS_WORKSHOP_VERSION = 'v1';
/**
* Class SteamWorkshopElem
*
* Handle custom HTML element to render Steam workshop widgets
*/
class SteamWorkshopElem extends HTMLElement
{
DESCRIPTION_MAX_LEN = 40;
storedData = {};
oldHeader = '';
connectedCallback()
{
var itemid = (typeof this.attributes.itemid !== 'undefined') ? this.attributes.itemid.value : null;
var views = (typeof this.attributes.views !== 'undefined') ? this.attributes.views.value : 'Views';
var subscriptions = (typeof this.attributes.subscriptions !== 'undefined') ? this.attributes.subscriptions.value : 'Subscriptions';
var favorites = (typeof this.attributes.favorites !== 'undefined') ? this.attributes.favorites.value : 'Favorites';
var author = (typeof this.attributes.author !== 'undefined') ? this.attributes.author.value : 'By :creator';
var viewtext = (typeof this.attributes.viewtext !== 'undefined') ? this.attributes.viewtext.value : 'View item';
var showImage = (typeof this.attributes['show-image'] !== 'undefined') ? parseInt(this.attributes['show-image'].value) : 1;
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;
if (itemid !== null) {
this.storedData = {
itemid: itemid,
views: views,
subscriptions: subscriptions,
favorites: favorites,
author: author,
viewtext: viewtext,
showImage: showImage,
styleBorder: styleBorder,
styleShadow: styleShadow
};
this.setupWidget(
itemid,
views,
subscriptions,
favorites,
author,
viewtext,
showImage,
styleBorder,
styleShadow
);
}
}
setupWidget(itemid, views, subscriptions, favorites, author, viewtext, showImage, styleBorder, styleShadow)
{
var req = new XMLHttpRequest();
var self = this;
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
let json = JSON.parse(req.responseText);
if (!document.getElementById('steamwidgets-workshop-styles')) {
let link = document.createElement('link');
link.id = 'steamwidgets-workshop-styles';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = STEAMWIDGETS_WORKSHOP_ENDPOINT + '/api/resource/query?type=css&module=workshop&version=' + STEAMWIDGETS_WORKSHOP_VERSION;
document.getElementsByTagName('head')[0].appendChild(link);
}
let description = json.data.description;
if (description.length >= self.DESCRIPTION_MAX_LEN) {
description = description.substr(0, self.DESCRIPTION_MAX_LEN - 3) + '...';
}
author = author.replace(':creator', json.data.creator_data.personaname);
let html = `
<div class="steam-workshop" ` + ((!styleShadow) ? 'style="box-shadow: unset;"' : '') + `>
<div class="steam-workshop-preview" style="background-image: url('` + json.data.preview_url + `'); ` + ((!showImage) ? 'display: none;' : '') + `"></div>
<div class="steam-workshop-info" ` + ((!showImage) ? 'style="top: 13px; width: 100%;"' : '') + `>
<div class="steam-workshop-info-title">` + json.data.title + `</div>
<div class="steam-workshop-info-description">` + description + `</div>
<div class="steam-workshop-info-stats">
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.views) + `</div>
<div class="steam-workshop-info-stats-item-label">` + views + `</div>
</div>
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.subscriptions) + `</div>
<div class="steam-workshop-info-stats-item-label">`+ subscriptions + `</div>
</div>
<div class="steam-workshop-info-stats-item">
<div class="steam-workshop-info-stats-item-count">` + self.readableCount(json.data.favorited) + `</div>
<div class="steam-workshop-info-stats-item-label">`+ favorites + `</div>
</div>
</div>
<div class="steam-workshop-info-footer">
<div class="steam-workshop-info-footer-author"><a href="` + json.data.creator_data.profileurl + `">` + author + `</a></div>
<div class="steam-workshop-info-footer-action">
<a href="https://steamcommunity.com/sharedfiles/filedetails/?id=` + json.data.publishedfileid + `">` + viewtext + `</a>
</div>
</div>
</div>
</div>
`;
self.innerHTML = html;
}
};
req.open('GET', STEAMWIDGETS_WORKSHOP_ENDPOINT + '/api/query/workshop?itemid=' + itemid, true);
req.send();
}
updateWidget()
{
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
changeLang(views, subscriptions, favorites, author, viewtext)
{
this.storedData.views = views;
this.storedData.subscriptions = subscriptions;
this.storedData.favorites = favorites;
this.storedData.author = author;
this.storedData.viewtext = viewtext;
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
setImageVisibility(visibility)
{
this.storedData.showImage = visibility;
this.setupWidget(
this.storedData.itemid,
this.storedData.views,
this.storedData.subscriptions,
this.storedData.favorites,
this.storedData.author,
this.storedData.viewtext,
this.storedData.showImage,
this.storedData.styleBorder,
this.storedData.styleShadow
);
}
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-workshop', SteamWorkshopElem);
/**
* Class SteamWorkshop
*
* Dynamically create a Steam workshop widgets via JavaScript
*/
class SteamWorkshop
{
elem = null;
selident = null;
cfg = {};
constructor(selector, config = {})
{
this.selident = selector;
this.cfg = config;
var itemid = (typeof config.itemid !== 'undefined') ? config.itemid : null;
var views = (typeof config.views !== 'undefined') ? config.views : 'Views';
var subscriptions = (typeof config.subscriptions !== 'undefined') ? config.subscriptions : 'Subscriptions';
var favorites = (typeof config.favorites !== 'undefined') ? config.favorites : 'Favorites';
var author = (typeof config.author !== 'undefined') ? config.author : 'By :creator';
var viewtext = (typeof config.viewtext !== 'undefined') ? config.viewtext : 'View item';
var showImage = (typeof config.showImage !== 'undefined') ? config.showImage : null;
if (typeof showImage === 'boolean') {
showImage = (showImage) ? 1 : 0;
}
var styleBorder = null;
var styleShadow = 1;
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;
}
if (typeof styleShadow === 'boolean') {
styleShadow = (styleShadow) ? 1 : 0;
}
this.elem = document.createElement('steam-workshop');
this.elem.setAttribute('itemid', itemid);
this.elem.setAttribute('views', views);
this.elem.setAttribute('subscriptions', subscriptions);
this.elem.setAttribute('favorites', favorites);
this.elem.setAttribute('author', author);
this.elem.setAttribute('viewtext', viewtext);
this.elem.setAttribute('show-image', showImage);
this.elem.setAttribute('style-border', styleBorder);
this.elem.setAttribute('style-shadow', styleShadow);
let sel = document.querySelector(selector);
if (sel) {
sel.appendChild(this.elem);
}
}
updateWidget()
{
this.elem.updateWidget();
}
changeLang(views, subscriptions, favorites, author, viewtext)
{
this.elem.changeLang(views, subscriptions, favorites, author, viewtext);
}
setImageVisibility(visibility)
{
this.elem.setImageVisibility(visibility);
}
remove()
{
this.elem.remove();
}
}