JSFiddle - React, Tailwind, and code Playground
by Gwyn Milcote
HTML
<!-- Panel, full width of page. -->
<div id='header-top'>
<!-- Actual content restricted to 1000px. -->
<div id='header-top-content'>
<!-- Username or HP/MP bars? Or if NLI, register link. -->
<div id='header-top-left'>
<span>Greetings, {username}!</span>
</div>
<!-- Logo in centre. -->
<div id='header-top-logo'>logo</div>
<!-- Mail, currencies, logout button. Or if NLI, login form. -->
<div id='header-top-right'>
<span class='icon' id='header-span-mail'>1</span>
<span class='separator'></span>
<span class='icon' id='header-span-coins'>86856</span>
<span class='separator'></span>
<span class='icon' id='header-span-gems'>83</span>
<span class='separator'></span>
<span class='icon' id='header-span-logout'></span>
</div>
</div>
</div>
<!-- Below top panel, row of navigation icons. -->
<div id='header-navbar'>
<ul id='navbar-content'></ul>
</div>
<!-- Begin main page, strictly inside container. -->
<div id='page-container'>
<!-- Quest/tutorial dialogue panel might be here. -->
<div id='quest-section'>[tutorial panel]</div>
<!-- Page content varies... -->
<!-- Large empty space where pet coat appears. -->
<div id='pp-coat-container'>
<div class='mythic-coat coat-adult'></div>
</div>
<!-- Pet's name, title, and arrows to next/last pets. -->
<div id='pp-banner'>
<div class='pp-banner-arrow'> < </div>
<div>
<div id='pp-banner-name'>Pet Name Goes Here</div>
<div id='pp-banner-title'>Pet Suffix Goes Here</div>
</div>
<div class='pp-banner-arrow'> > </div>
</div>
<!-- Pet profile has 3 columns. -->
<div id='pp-container'>
<div class='pp-column-side'>
<!-- Status -->
<div class='pp-section'>
<div class='pp-section-top'>
<div class='pp-section-question hover-outer'>?
<div class='hover-inner hover-inner-question'>How is your Mythic feeling right now? Be sure...
CSS
@import url('https://fonts.googleapis.com/css?family=Alegreya');
div, img, canvas, button, ul, li, p, a, table, tr, td {
box-sizing: border-box;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
font-family: 'Alegreya', sans-serif;
color: rgba(0, 0, 0, 0.8);
}
body {
background-image: url("https://2.bp.blogspot.com/_1PJ0u0wnGBA/TMF46D3ZEtI/AAAAAAAADjA/yugNSRhtDTU/s1600/Storm+Clouds+05.jpg");
background-size: cover;
background-attachment: fixed;
}
a {
text-decoration: none;
}
/* Top of every page. Contains logo, user status. */
/* Below that, row of nav icons with dropdown menus. */
#header {
}
/* Full width of page. */
#header-top {
width: 100%;
height: 42px;
background-image: url("header-top.png");
background-color: #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.8);
}
#header-top-content {
width: 980px;
margin: auto;
position: relative;
}
#header-top-content span {
display: inline-block;
text-shadow: 0px 1px 1px #fff;
}
#header-top-left, #header-top-right {
width: 340px;
height: 40px;
position: absolute;
top: 0;
border: 1px dotted red;
display: flex;
flex-flow: row;
align-items: center;
}
#header-top-left {
left: 0;
}
#header-top-right {
right: 0;
justify-content: right;
text-align: right;
}
#header-top-logo {
width: 300px;
height: 50px;
position: absolute;
top: 0;
left: 340px;
/* Navbar is 2, so this must be above, partly covering the top */
z-index: 3;
background-color: rgba(255, 255, 255, 0.9);
box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.4);
background-image: url("header-logo.png");
}
/* Icons all on same sheet. Change background-position. */
#header-top-content span.separator {
height: 20px;
width: 2px;
margin: 0px 10px;
background-image: url("header-icons.png");
background-position: 0 0;
background-color: rgba(0, 0, 0, 0.8);
}
#header-top-content span.icon {
height: 20px;
background-image:...
JavaScript
// General utility funcs, include in main JS file.
function getSkillName(id){
let skillNames = [
"Botany","Culinary","Geology","Metals",
"Craft","Building","Science!","Textiles",
"Combat","Toughness","Tracking","Agility",
"Healing","Magic","Animals","Aquatics"
];
if(id < 1 || id > skillNames.length){
throw "getSkillName(): invalid ID, '" + id + "'.";
}
return skillNames[id - 1];
}
// Search an array of objects, by one property.
function findById(array,id){
return array[id];
}
function findByProperty(array,prop,value){
return array[id];
}
function sortByProperty(array,prop){
return array;
}
// When click + or - icon in a box's top right corner,
// toggle the section's content on or off.
$(".pp-section-toggle").on("click", function(){
let section = $(this).data("section"),
span = $("#pp-toggle-" + section);
if(span.css("display") == "none"){
span.show();
}else{
span.hide();
}
});
// Store a bunch of pet vars... for easy reference/calcs/updating?
// Howrse does it, so it can't be a terrible idea.
let mythicInfo = {
id: 7832,
name: "Caristo",
sex: 2,
breed: 6,
stage: 5,
age: 127,
energy: 89,
health: 68,
mood: 99,
belly: 56,
skills: [
25,19,27,72,
18,10,73,16,
9,0,17,128,
47,297,238,70
]
};
class MythicProfile {
constructor(data){
this.pet = data;
// These should be available immediately.
this.customisation = {
background: {id: 6, name: "Lavender Field"},
scenery: [
{
id: 1, layer: 3, vis: 1,
name: "[Scenery] Fireflies"
},{
id: 2, layer: 1, vis: 0,
name: "[Scenery] Mist"
},{
id: 3, layer: 2, vis: 1,
name: "[Scenery] Tall Grass"
},{
id: 4, layer: 6, vis: 1,
name: "[Scenery] Butterflies"
},{
id: 5, layer: 4, vis: 0,
name: "[Scenery] Cherry Blossom"
},{
id: 6, layer: 5, vis: 1,
name: "[Scenery] Ember Rain"
},{
...