This commit is contained in:
Dan Chadwick
2024-04-09 01:47:04 +00:00
parent 3bcbe3b783
commit 3cfd95ee81
219 changed files with 47894 additions and 3767 deletions

View File

@@ -1,102 +1,253 @@
@import url("https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap");
.ubuntu-light {
font-family: "Ubuntu", sans-serif;
header {
display: flex;
width: 100%;
justify-content: center;
padding: 0.5rem 0;
}
header > div {
display: flex;
justify-content: space-between;
width: 1152px;
align-items: center;
}
header .navbar-nav {
flex-direction: row !important;
}
header .navbar-nav li:not(:last-child) {
border-right: 2px solid #f4e8d9;
}
header .navbar-nav a.nav-link {
padding: 0 1rem;
text-decoration: none;
transition: color 0.2s ease-in-out;
}
header .navbar-nav a.nav-link:hover {
color: #f6c177;
}
#block-dchadwick-primary-local-tasks > ul {
list-style: none;
display: flex;
justify-content: center;
margin: 0;
}
#block-dchadwick-primary-local-tasks > ul li {
padding: 0.5rem 1rem;
background: #fffaf3;
border-bottom: 2px solid #9ccfd8;
border-right: 2px solid #9ccfd8;
}
#block-dchadwick-primary-local-tasks > ul li:first-child {
border-left: 2px solid #9ccfd8;
}
#block-dchadwick-primary-local-tasks > ul li a {
font-size: 0.8rem;
text-decoration: none;
transition: color 0.2s ease-in-out;
}
#block-dchadwick-primary-local-tasks > ul li a:hover {
color: #f6c177;
}
.main::before {
content: "";
display: block;
width: 100%;
background: #9ccfd8;
height: 1rem;
}
main {
max-width: 1152px;
margin: auto;
}
#fighter__personal-info .fieldset-wrapper, #fighter__stats .fieldset-wrapper {
display: flex;
flex-flow: wrap;
justify-content: space-evenly;
}
#fighter__stats .fieldset-wrapper > div {
flex-basis: 20%;
}
#fighter h2 {
text-align: center;
font-size: 3rem;
margin: 4rem 0;
text-transform: uppercase;
}
#fighter span.label {
font-size: 1.2rem;
font-weight: 300;
font-style: normal;
}
#fighter .data-wrapper {
margin: 1rem;
}
#fighter .datapoint {
font-size: 2rem;
}
#fighter__hero {
color: #f6c177;
display: flex;
flex-flow: wrap;
padding: 2rem 0;
justify-content: space-evenly;
align-items: center;
}
#fighter__text {
text-align: center;
background: #1f1d2e;
padding: 2rem 3rem;
border: 1px solid;
}
#fighter__text h1 {
margin-top: 0;
margin-bottom: 1rem;
font-size: 2.4rem;
}
#fighter__personal {
display: flex;
flex-flow: wrap;
justify-content: space-evenly;
text-align: center;
}
#fighter__stats {
display: flex;
flex-flow: wrap;
justify-content: space-between;
text-align: center;
}
.ubuntu-light-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 300;
font-style: italic;
h2#fight-history {
text-align: center;
color: #6e6a86;
font-size: 3rem;
margin: 2rem 0;
text-transform: uppercase;
}
.ubuntu-regular {
font-family: "Ubuntu", sans-serif;
font-weight: 400;
font-style: normal;
table.cols-2 {
margin: auto;
width: auto;
text-align: center;
color: #f6c177;
}
table.cols-2 thead tr {
font-size: 1.6rem;
background: #191724 !important;
}
table.cols-2 thead tr th {
padding: 10px 0;
}
table.cols-2 tr:nth-child(odd) {
background: #fffaf3;
}
table.cols-2 tr:nth-child(odd) a {
color: #191724;
}
table.cols-2 tbody > tr > td {
padding: 1rem;
}
table.cols-2 tbody > tr > td a {
text-decoration: none;
}
.ubuntu-regular-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 400;
font-style: italic;
td.loss {
background: #eb6f92;
--bs-table-striped-color: #eb6f92;
--bs-table-color-type: var(--bs-table-striped-color);
--bs-table-bg-type: var(--bs-table-striped-bg);
}
td.loss a {
color: white !important;
}
.ubuntu-medium {
font-family: "Ubuntu", sans-serif;
font-weight: 500;
font-style: normal;
td.win {
background: #9ccfd8;
}
td.win a {
color: white !important;
}
.ubuntu-medium-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 500;
font-style: italic;
.page-node-type-fighter .table > :not(caption) > * > * {
box-shadow: none !important;
}
.ubuntu-bold {
font-family: "Ubuntu", sans-serif;
font-weight: 700;
font-style: normal;
.view-all-fighters .view-content {
display: flex;
flex-flow: wrap;
}
.view-all-fighters .view-content .card img {
max-height: 214px;
}
.view-all-fighters .view-content .btn-dark {
margin-left: 0;
}
.view-all-fighters .view-content .btn-dark a {
text-decoration: none;
}
.ubuntu-bold-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 700;
font-style: italic;
.page-node-type-fight h1 {
text-align: center;
}
.page-node-type-fight #block-dchadwick-content {
display: flex;
justify-content: center;
}
.page-node-type-fight th {
padding: 1rem 1rem 0 1rem !important;
text-align: center;
}
.page-node-type-fight th a {
text-decoration: none;
}
.page-node-type-fight th.win {
color: white;
background: #9ccfd8;
}
#compare-fighters img {
max-width: 100px;
}
table.cols-5 {
border-spacing: 2rem 0;
margin-top: 2rem;
}
table.cols-5 thead {
text-align: left;
}
table.cols-5 tbody tr:nth-child(odd) {
background: #fffaf3;
}
table.cols-5 td {
padding: 5px 0;
}
table.cols-5 td.correct {
background: #9ccfd8 !important;
color: white;
}
table.cols-5 td.incorrect {
background: #eb6f92;
color: white;
}
body {
background: #191724;
color: #e0def4;
background: #faf4ed;
color: #6e6a86;
font-family: "Ubuntu", sans-serif;
margin: auto;
}
a {
color: #f6c177;
}
a:visited {
color: #9ccfd8;
}
header {
background: #1f1d2e;
border: 1px solid #eb6f92;
}
header div > * {
display: inline-block;
}
header div#block-dchadwick-site-branding {
padding: 1rem;
}
header div#block-dchadwick-site-branding a {
text-decoration: none;
font-weight: 700;
}
header div#block-dchadwick-site-branding a:visited {
color: #f6c177 !important;
color: #6e6a86;
}
img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
header {
background: #1f1d2e;
border: 1px solid #eb6f92;
}
header div > * {
display: inline-block;
}
header div#block-dchadwick-site-branding {
padding: 1rem;
}
header div#block-dchadwick-site-branding a {
text-decoration: none;
font-weight: 700;
}
header div#block-dchadwick-site-branding a:visited {
color: #f6c177 !important;
}

View File

@@ -5,9 +5,8 @@ package: Other
core_version_requirement: ^9 || ^10
libraries:
- dchadwick/global-styling
- dchadwick/htmx
base theme: stark
base theme: bootstrap5
regions:
navigation: Main navigation
content: Content

View File

@@ -1,17 +1,28 @@
global-styling:
version: 1.x
js:
js/global.js: {}
js/global.js: { }
css:
theme:
css/style.css: {}
htmx:
remote: https://github.com/bigskysoftware/htmx
version: 1.9.10
license:
name: Zero-Clause BSD
url: https://github.com/bigskysoftware/htmx/blob/master/LICENSE
gpl-compatible: true
# dcjs:
# version: 1.x
# js:
# js/dcjs/dcjs.js: { attributes: { async: true, defer: false} }
predict_fight:
version: 1.x
js:
https://github.com/bigskysoftware/htmx/blob/v1.9.10/dist/htmx.min.js: { type: external, minified: true }
js/predictFight.js: { attributes: { await: true }}
predict_event:
version: 1.x
js:
js/predictEvent.js: { attributes: { await: true }}
brainjs:
version: 2.0.0
js:
https://unpkg.com/brain.js@2.0.0-beta.23/dist/browser.js: { type: external, attributes: { async: true }}

View File

@@ -0,0 +1,81 @@
<?php
use Drupal\node\NodeInterface;
function dchadwick_page_attachments_alter(&$page) {
$page['#attached']['library'][] = 'dchadwick/brainjs';
}
function dchadwick_preprocess_node__fighter(&$vars) {
$fighter_node = \Drupal::routeMatch()->getParameter('node');
if (!$fighter_node) {
return;
}
assert($fighter_node instanceof NodeInterface);
// Need to ensure the type here.
assert($fighter_node->bundle() == 'fighter');
$personal_fields = [
'age',
'division',
'height',
'weight',
'reach',
'leg_reach',
];
$stats_fields = [
'knockouts',
'striking_accuracy',
'strikes_per_minute',
'sig_strike_defense',
'absorbed_per_min',
'standing_strikes',
'clinch_strikes',
'ground_strikes',
'grappling_accuracy',
'strikes_to_head',
'strikes_to_body',
'strikes_to_leg',
'knockdown_ratio',
'takedowns_per_15',
'takedown_defense',
'average_fight_time',
'first_round_finishes',
];
$vars['personal_info'] = get_field_values_from_node($fighter_node, $personal_fields);
$vars['stats'] = get_field_values_from_node($fighter_node, $stats_fields);
}
/**
* Extracts target field values from a node.
*
* @param NodeInterface $node
* The node.
*
* @param array[] $retrieve
* The fields to retrieve
*
* @return array[]
*/
function get_field_values_from_node(NodeInterface $node, array $retrieve): array {
$return_data = [];
foreach ($retrieve as $field_name) {
$field_name_with_prefix = "field_$field_name";
if ($field_name == 'division') {
if ($node->hasField($field_name_with_prefix)) {
$div_id = $node->get($field_name_with_prefix)->target_id;
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($div_id);
$return_data['division'] = $term->getName();
}
}
else {
if ($node->hasField($field_name_with_prefix)) {
$return_data[$field_name] = $node->{$field_name_with_prefix}->value;
}
}
}
return $return_data;
}

View File

@@ -6,6 +6,7 @@ var gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
var input = './src/sass/*.scss';
var output = './css';
var partials = './src/sass/partials/*.scss';
gulp.task('sass', function () {
return gulp
@@ -16,3 +17,7 @@ gulp.task('sass', function () {
// Write the resulting CSS in the output folder.
.pipe(gulp.dest(output));
});
gulp.task('watch', function () {
gulp.watch([input, partials], gulp.series('sass'));
});

View File

@@ -1 +1,58 @@
console.log("hello from my custom js file.")
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
highlightFightHistory();
let train = false;
if (train) {
trainTheBrain();
}
}
}, { passive: true });
function highlightFightHistory() {
let historyTable = document.querySelector('table.cols-2');
if (!historyTable) {
return;
}
const fighterName = document.querySelector('#fighter h1').innerText;
let winnerCols = historyTable.querySelectorAll('tbody tr td:last-child');
for (let winnerCol of winnerCols) {
if (winnerCol.innerText == fighterName) {
winnerCol.classList.add("win");
}
else {
winnerCol.classList.add("loss");
}
}
}
function trainTheBrain() {
const config = {
iterations: 50000,
log: true,
logPeriod: 1000,
binaryThresh: 0.5,
hiddenLayers: [40, 20], // array of ints for the sizes of the hidden layers in the network
activation: 'sigmoid', // supported activation types: ['sigmoid', 'relu', 'leaky-relu', 'tanh'],
learningRate: 0.05,
momentum: 0.2,
decayRate: 0.999,
};
// create a simple feed-forward neural network with backpropagation
const net = new brain.NeuralNetwork(config);
// Get contents from http://localhost/api/v1/training-data
fetch("/api/v1/training-data").then(res => res.json()).then(data => {
obj = data
})
.then(() => {
console.log("Training...");
net.train(obj);
localStorage.setItem('neuralNetwork', JSON.stringify(net.toJSON()));
console.log("Neural Network stored in LocalStorage");
});
}

View File

@@ -0,0 +1,73 @@
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") {
document.querySelector("table.cols-5").classList.remove("table-striped");
setTimeout(() => {
predictEvent();
}, 500);
}
}, { passive: true });
async function getNetwork() {
let obj;
const res = await fetch('/api/v1/network');
obj = await res.json();
return obj;
}
function predictFights(network) {
let fights = document.querySelectorAll("table.cols-5 tbody .fight");
fights.forEach((fight) => {
let result = fight.querySelector('.views-field-field-result');
let resultText = result.textContent.trim();
let fightIdDiv = fight.querySelector('.views-field-field-fighter-one div');
let fightId = "";
if (fightIdDiv) {
fightId = fightIdDiv.dataset.id;
}
if (fightId.length > 0) {
const fightDataEndpoint = '/api/v1/fight-data/' + fightId;
fetch(fightDataEndpoint).then(res => res.json()).then(data => {
obj = data
})
.then(() => {
let predictions = network.run(obj);
if (predictions.fighter_one > predictions.fighter_two) {
// Get fighter one name and set as prediction.
let f1Name = fight.querySelector('.views-field-field-fighter-one').textContent.trim();
fight.lastElementChild.textContent = f1Name + " (" + Number.parseFloat(predictions.fighter_one * 100).toFixed(4) + " %)";
if (f1Name == resultText) {
fight.lastElementChild.classList.add("correct");
} else {
fight.lastElementChild.classList.add("incorrect");
}
} else {
// Get fighter two name and set as prediction.
let f2Name = fight.querySelector('.views-field-field-fighter-two').textContent.trim();
fight.lastElementChild.textContent = f2Name + " (" + Number.parseFloat(predictions.fighter_two * 100).toFixed(4) + " %)";
if (f2Name == resultText) {
fight.lastElementChild.classList.add("correct");
} else {
fight.lastElementChild.classList.add("incorrect");
}
}
});
}
});
}
function predictEvent() {
const net = new brain.NeuralNetwork();
let curNet = getNetwork();
curNet
.then(res => {
net.fromJSON(JSON.parse(res.data));
predictFights(net);
})
.catch(error => {console.log("i got issues")});
}

View File

@@ -0,0 +1,36 @@
document.addEventListener('readystatechange', event => {
// When HTML/DOM elements are ready:
if (event.target.readyState === "interactive") { //does same as: ..addEventListener("DOMContentLoaded"..
setTimeout(() => {
predictFight();
}, 500);
}
}, { passive: true });
function predictFight() {
let fight = document.getElementById("fight");
let fightId = fight.dataset.fight;
const net = new brain.NeuralNetwork();
net.fromJSON(
JSON.parse(
localStorage.getItem('neuralNetwork')
)
);
const fightDataEndpoint = '/api/v1/fight-data/' + fightId;
fetch(fightDataEndpoint).then(res => res.json()).then(data => {
obj = data
})
.then(() => {
let results = net.run(obj);
let headerRowItems = document.querySelectorAll('#compare-fighters thead th');
if (results.fighter_one > results.fighter_two) {
headerRowItems[1].classList.add("win");
}
else {
headerRowItems[2].classList.add("win");
}
console.log(results);
});
}

View File

@@ -5,7 +5,8 @@
"main": "gulpfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"compile": "gulp sass"
"compile": "gulp sass",
"watch": "gulp watch"
},
"author": "",
"license": "ISC",

Binary file not shown.

View File

@@ -1,4 +0,0 @@
img {
max-width: 100%;
max-height: 100%;
}

View File

@@ -0,0 +1,32 @@
table.cols-5 {
border-spacing: 2rem 0;
margin-top: 2rem;
thead {
text-align: left;
}
tbody {
tr:nth-child(odd) {
background: $surface;
}
}
td {
padding: 5px 0;
}
td.correct {
background: $foam !important;
color: white;
}
td.incorrect {
background: $love;
color: white;
}
}

View File

@@ -0,0 +1,31 @@
.page-node-type-fight {
h1 {
text-align: center;
}
#block-dchadwick-content {
display: flex;
justify-content: center;
}
th {
padding: 1rem 1rem 0 1rem !important;
text-align: center;
a {
text-decoration: none;
}
}
th.win {
color: white;
background: $foam;
}
}
#compare-fighters {
img {
max-width: 100px;
}
}

View File

@@ -0,0 +1,134 @@
#fighter {
&__personal-info, &__stats {
.fieldset-wrapper {
display: flex;
flex-flow: wrap;
justify-content: space-evenly;
}
}
&__stats {
.fieldset-wrapper > div {
flex-basis: 20%;
}
}
}
#fighter {
h2 {
text-align: center;
font-size: 3rem;
margin: 4rem 0;
text-transform: uppercase;
}
span.label {
font-size: 1.2rem;
font-weight: 300;
}
.data-wrapper {
margin: 1rem;
}
.datapoint {
font-size: 2rem;
}
&__hero {
color: $orangeish;
display: flex;
flex-flow: wrap;
padding: 2rem 0;
justify-content: space-evenly;
align-items: center;
}
&__text {
h1 {
margin-top: 0;
margin-bottom: 1rem;
font-size: 2.4rem;
}
text-align: center;
background: $overlay_bl;
padding: 2rem 3rem;
border: 1px solid;
}
&__personal {
display: flex;
flex-flow: wrap;
justify-content: space-evenly;
text-align: center;
}
&__stats {
display: flex;
flex-flow: wrap;
justify-content: space-between;
text-align: center;
}
}
h2#fight-history {
text-align: center;
color: $muted;
font-size: 3rem;
margin: 2rem 0;
text-transform: uppercase;
}
table.cols-2 {
margin: auto;
width: auto;
text-align: center;
color: $orangeish;
thead tr {
font-size: 1.6rem;
background: $base_bl !important;
th {
padding: 10px 0;
}
}
tr:nth-child(odd) {
background: $surface;
a {
color: $base_bl;
}
}
tbody > tr > td {
padding: 1rem;
a {
text-decoration: none;
}
}
}
td.loss {
background: $love;
--bs-table-striped-color: #eb6f92;
--bs-table-color-type: var(--bs-table-striped-color);
--bs-table-bg-type: var(--bs-table-striped-bg);
a {
color: white !important;
}
}
td.win {
background: $foam;
a {
color: white !important;
}
}
.page-node-type-fighter {
.table > :not(caption) > * > * {
box-shadow: none !important;
}
}

View File

@@ -0,0 +1,16 @@
.view-all-fighters .view-content {
display: flex;
flex-flow: wrap;
.card img {
max-height: 214px;
}
.btn-dark {
margin-left: 0;
a {
text-decoration: none;
}
}
}

View File

@@ -1,17 +1,83 @@
header {
background: $overlay_bl;
border: 1px solid $love;
div > * {
display: inline-block;
display: flex;
width: 100%;
justify-content: center;
padding: .5rem 0;
> div {
display: flex;
justify-content: space-between;
width: $container-full;
align-items: center;
}
div#block-dchadwick-site-branding {
padding: 1rem;
a {
.navbar-nav {
flex-direction: row !important;
li:not(:last-child) {
border-right: 2px solid darken($base_light, 5%);
}
a.nav-link {
padding: 0 1rem;
text-decoration: none;
font-weight: 700;
&:visited {
color: $gold !important;
transition: color .2s ease-in-out;
&:hover {
color: $orangeish;
}
}
}
}
// header {
// display: flex;
// width: 100%;
// justify-content: center;
// color: $muted;
// > div {
// display: flex;
// justify-content: space-between;
// width: $container-full;
// // Need to add media queries to adjust on smaller screens.
// align-items: center;
// background: $surface;
// padding: 0 2rem;
// border-radius: 5px 5px 0 0;
// }
// #block-dchadwick-main-menu {
// > ul {
// display: flex;
// list-style-type: none;
// > li {
// padding: 0 1rem;
// a {
// text-decoration: none;
// transition: color .2s ease-in-out;
// &:hover {
// color: $orangeish;
// }
// }
// &:not(:last-child) {
// border-right: 2px solid darken($base_light, 5%);
// }
// }
// }
// }
// div#block-dchadwick-site-branding {
// padding: 1.5rem 0;
// > a {
// text-decoration: none;
// // padding-left: 1rem;
// white-space: nowrap;
// width: auto;
// font-weight: 700;
// font-size: 1.4rem;
// }
// }
// }

View File

@@ -0,0 +1,27 @@
#block-dchadwick-primary-local-tasks {
> ul {
list-style: none;
display: flex;
justify-content: center;
margin: 0;
li {
padding: .5rem 1rem;
background: $surface;
border-bottom: 2px solid $foam;
&:first-child {
border-left: 2px solid $foam;
}
border-right: 2px solid $foam;
a {
font-size: 0.8rem;
text-decoration: none;
transition: color .2s ease-in-out;
&:hover {
color: $orangeish;
}
}
}
}
}

View File

@@ -0,0 +1,14 @@
.main {
&::before {
content: "";
display: block;
width: 100%;
background: $foam;
height: 1rem;
}
}
main {
max-width: $container-full;
margin: auto;
}

View File

@@ -1,100 +1,55 @@
// Colors.
$base_light: #faf4ed;
$base_bl: #191724;
$overlay_bl: #1f1d2e;
$muted: #6e6a86;
$subtle: #908caa;
$surface: #fffaf3;
$text: #e0def4;
$love: #eb6f92;
$gold: #f6c177;
$orangeish: #f6c177;
$rose: #ebbcba;
$pine: #31748f;
$foam: #9ccfd8;
$iris: #c4a7e7;
$link-color: $foam;
// Bootstrap overrides.
$primary: $surface;
$secondary: $base_bl;
$link_color: pink;
$link_hover_color: pink;
$a_link_hover_color: pink;
// Other variables.
$container-full: 1152px;
$container-plus-padding: 1216px;
// Google fonts.
@import url("https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap");
.ubuntu-light {
font-family: "Ubuntu", sans-serif;
font-weight: 300;
font-style: normal;
}
.ubuntu-light-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 300;
font-style: italic;
}
.ubuntu-regular {
font-family: "Ubuntu", sans-serif;
font-weight: 400;
font-style: normal;
}
.ubuntu-regular-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 400;
font-style: italic;
}
.ubuntu-medium {
font-family: "Ubuntu", sans-serif;
font-weight: 500;
font-style: normal;
}
.ubuntu-medium-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 500;
font-style: italic;
}
.ubuntu-bold {
font-family: "Ubuntu", sans-serif;
font-weight: 700;
font-style: normal;
}
.ubuntu-bold-italic {
font-family: "Ubuntu", sans-serif;
font-weight: 700;
font-style: italic;
}
// Partials.
@import "partials/header";
@import "partials/local-tasks";
@import "partials/main";
@import "partials/fighter";
@import "partials/fighters-view";
@import "partials/fight";
@import "partials/event";
body {
background: $base_bl;
color: $text;
background: $base_light;
color: $muted;
font-family: "Ubuntu", sans-serif;
margin: auto;
}
a {
color: $gold;
&:visited {
color: $foam;
}
color: $muted;
}
img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
// Imports.
@import "partials/header";
@import "partials/articles";
header {
background: $overlay_bl;
border: 1px solid $love;
div > * {
display: inline-block;
}
div#block-dchadwick-site-branding {
padding: 1rem;
a {
text-decoration: none;
font-weight: 700;
&:visited {
color: $gold !important;
}
}
}
}

View File

@@ -0,0 +1,47 @@
{#
/**
* @file
* Theme override to display a block.
*
* Available variables:
* - plugin_id: The ID of the block implementation.
* - label: The configured label of the block if visible.
* - configuration: A list of the block's configuration values.
* - label: The configured label for the block.
* - label_display: The display settings for the label.
* - provider: The module or other provider that provided this block plugin.
* - Block plugin specific settings will also be stored here.
* - in_preview: Whether the plugin is being rendered in preview mode.
* - content: The content of this block.
* - attributes: array of HTML attributes populated by modules, intended to
* be added to the main container tag of this template.
* - id: A valid HTML ID and guaranteed unique.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
*
* @see template_preprocess_block()
*/
#}
{%
set classes = [
'block',
'block-' ~ configuration.provider|clean_class,
'block-' ~ plugin_id|clean_class,
'hero-block',
]
%}
<div{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if label %}
<h2{{ title_attributes }}>{{ label }}</h2>
{% endif %}
{{ title_suffix }}
{% block content %}
{{ dump(content) }}
{{ content }}
{% endblock %}
</div>

View File

@@ -0,0 +1,15 @@
{% set buttonType, buttonText, uri = type, text, uri %}
{% if buttonType %}
<button type="button" class="btn btn-{{ buttonType }}">
{% else %}
<button type="button" class="btn btn-primary">
{% endif %}
{% if uri %}
<a href="{{ uri }}">{{ text }}</a>
{% else %}
{{ text }}
{% endif %}
</button>

View File

@@ -0,0 +1,24 @@
<div class="card" style="width: 18rem;">
{% set fighterImg = file_url(node.field_player_photo.entity.field_media_image.entity.uri.value) %}
{% set fighterAlias = path('entity.node.canonical', { 'node': node.id }) %}
<img src="{{ fighterImg }}" class="card-img-top">
<div class="card-body">
{% include '@dchadwick/components/heading.html.twig' with {
'heading': '4',
'text': title
} %}
<h6 class="card-subtitle mb-2 text-muted">{{ wins }} - {{ losses }} - {{ ties }}</h6>
{% include '@dchadwick/components/button.html.twig' with {
'uri': fighterAlias,
'type': 'dark',
'text': 'View Fighter'
} %}
</div>
</div>

View File

@@ -0,0 +1 @@
<h{{ heading }} attributes.addClass(classes)>{{ text }}</h{{ heading }}>

View File

@@ -0,0 +1,138 @@
{#
/**
* @file
* Default theme implementation to display a node.
*
* @ingroup themeable
*/
#}
{{ attach_library('dchadwick/predict_fight') }}
{% set fighter_1 = node.field_fighter_one.entity %}
{% set fighter_2 = node.field_fighter_two.entity %}
{% set fighter1img = file_url(fighter_1.field_player_photo.entity.field_media_image.entity.uri.value) %}
{% set fighter2img = file_url(fighter_2.field_player_photo.entity.field_media_image.entity.uri.value) %}
<article{{ attributes }} id="fight" data-fight="{{ node.id }}">
<div{{ content_attributes }}>
<table class="align-center mx-auto w-auto table-bordered table table-striped" id="compare-fighters">
<thead>
<th></th>
<th><a href="/node/{{ fighter_1.id }}">{{ node.field_fighter_one.entity.getTitle() }}<br/><img src="{{ fighter1img }}"/></a></th>
<th><a href="/node/{{ fighter_2.id }}">{{ node.field_fighter_two.entity.getTitle() }}<br/><img src="{{ fighter2img }}"/></a></th>
</thead>
<tbody>
<tr>
<td>Record</td>
<td>{{ fighter_1.field_wins.value }} - {{ fighter_1.field_losses.value }} - {{ fighter_1.field_ties.value }}</td>
<td>{{ fighter_2.field_wins.value }} - {{ fighter_2.field_losses.value }} - {{ fighter_2.field_ties.value }}</td>
</tr>
<tr>
<td>Age</td>
<td>{{ fighter_1.field_age.value }}</td>
<td>{{ fighter_2.field_age.value }}</td>
</tr>
<tr>
<td>Height</td>
<td>{{ fighter_1.field_height.value }}</td>
<td>{{ fighter_2.field_height.value }}</td>
</tr>
<tr>
<td>Reach</td>
<td>{{ fighter_1.field_reach.value }}</td>
<td>{{ fighter_2.field_reach.value }}</td>
</tr>
<tr>
<td>Leg Reach</td>
<td>{{ fighter_1.field_leg_reach.value }}</td>
<td>{{ fighter_2.field_leg_reach.value }}</td>
</tr>
<tr>
<td>Knockouts</td>
<td>{{ fighter_1.field_knockouts.value }}</td>
<td>{{ fighter_2.field_knockouts.value }}</td>
</tr>
<tr>
<td>Striking Accuracy</td>
<td>{{ fighter_1.field_striking_accuracy.value }}</td>
<td>{{ fighter_2.field_striking_accuracy.value }}</td>
</tr>
<tr>
<td>Strikes Per Min.</td>
<td>{{ fighter_1.field_strikes_per_minute.value }}</td>
<td>{{ fighter_2.field_strikes_per_minute.value }}</td>
</tr>
<tr>
<td>Sig Strike Defense</td>
<td>{{ fighter_1.field_sig_strike_defense.value }}</td>
<td>{{ fighter_2.field_sig_strike_defense.value }}</td>
</tr>
<tr>
<td>Absorbed per min.</td>
<td>{{ fighter_1.field_absorbed_per_min.value }}</td>
<td>{{ fighter_2.field_absorbed_per_min.value }}</td>
</tr>
<tr>
<td>Standing Strikes</td>
<td>{{ fighter_1.field_standing_strikes.value }}</td>
<td>{{ fighter_2.field_standing_strikes.value }}</td>
</tr>
<tr>
<td>Clinch Strikes</td>
<td>{{ fighter_1.field_clinch_strikes.value }}</td>
<td>{{ fighter_2.field_clinch_strikes.value }}</td>
</tr>
<tr>
<td>Ground Strikes</td>
<td>{{ fighter_1.field_ground_strikes.value }}</td>
<td>{{ fighter_2.field_ground_strikes.value }}</td>
</tr>
<tr>
<td>Grappling Accuracy</td>
<td>{{ fighter_1.field_grappling_accuracy.value }}</td>
<td>{{ fighter_2.field_grappling_accuracy.value }}</td>
</tr>
<tr>
<td>Strikes to Head</td>
<td>{{ fighter_1.field_strikes_to_head.value }}</td>
<td>{{ fighter_2.field_strikes_to_head.value }}</td>
</tr>
<tr>
<td>Strikes to Body</td>
<td>{{ fighter_1.field_strikes_to_body.value }}</td>
<td>{{ fighter_2.field_strikes_to_body.value }}</td>
</tr>
<tr>
<td>Strikes to Leg</td>
<td>{{ fighter_1.field_strikes_to_leg.value }}</td>
<td>{{ fighter_2.field_strikes_to_leg.value }}</td>
</tr>
<tr>
<td>Knockdown Ratio</td>
<td>{{ fighter_1.field_knockdown_ratio.value }}</td>
<td>{{ fighter_2.field_knockdown_ratio.value }}</td>
</tr>
<tr>
<td>Takedowns per 15</td>
<td>{{ fighter_1.field_takedowns_per_15.value }}</td>
<td>{{ fighter_2.field_takedowns_per_15.value }}</td>
</tr>
<tr>
<td>Takedown Defense</td>
<td>{{ fighter_1.field_takedown_defense.value }}</td>
<td>{{ fighter_2.field_takedown_defense.value }}</td>
</tr>
<tr>
<td>Average Fight Time</td>
<td>{{ fighter_1.field_average_fight_time.value }}</td>
<td>{{ fighter_2.field_average_fight_time.value }}</td>
</tr>
<tr>
<td>First Round Finishes</td>
<td>{{ fighter_1.field_first_round_finishes.value }}</td>
<td>{{ fighter_2.field_first_round_finishes.value }}</td>
</tr>
</tbody>
</table>
</div>
</article>

View File

@@ -0,0 +1,90 @@
{#
/**
* @file
* Theme override to display a node.
*
* Available variables:
* - node: The node entity with limited access to object properties and methods.
* Only method names starting with "get", "has", or "is" and a few common
* methods such as "id", "label", and "bundle" are available. For example:
* - node.getCreatedTime() will return the node creation timestamp.
* - node.hasField('field_example') returns TRUE if the node bundle includes
* field_example. (This does not indicate the presence of a value in this
* field.)
* - node.isPublished() will return whether the node is published or not.
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
* of a given child element.
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - node: The current template type (also known as a "theming hook").
* - node--type-[type]: The current node type. For example, if the node is an
* "Article" it would result in "node--type-article". Note that the machine
* name will often be in a short form of the human readable label.
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
* teaser would result in: "node--view-mode-teaser", and
* full: "node--view-mode-full".
* The following are controlled through the node publishing options.
* - node--promoted: Appears on nodes promoted to the front page.
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
* teaser listings.
* - node--unpublished: Appears on unpublished nodes visible only to site
* admins.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - content_attributes: Same as attributes, except applied to the main
* content tag that appears in the template.
* - author_attributes: Same as attributes, except applied to the author of
* the node tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
* - view_mode: View mode; for example, "teaser" or "full".
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
* - readmore: Flag for more state. Will be true if the teaser content of the
* node cannot hold the main body content.
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* @see template_preprocess_node()
*
*/
#}
{%
set classes = [
'node',
'node--type-' ~ node.bundle|clean_class,
node.isPromoted() ? 'node--promoted',
node.isSticky() ? 'node--sticky',
not node.isPublished() ? 'node--unpublished',
view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
]
%}
{{ attach_library('bootstrap5/node') }}
<div{{ attributes.addClass(classes) }}>
{% include '@dchadwick/components/card.html.twig' with {
'title': node.getTitle(),
'wins': node.field_wins.value,
'losses': node.field_losses.value,
'ties': node.field_ties.value
} %}
</div>

View File

@@ -0,0 +1,52 @@
{# attach_library('ufc/dcjs') #}
{% set fighterId = node.id %}
{% set fighterImg = file_url(node.field_player_photo.entity.field_media_image.entity.uri.value) %}
<div dc-get="/dcjs/fighter/{{ fighterId }}" dc-target="fighter-container" dc-trigger="load">
<div id="fighter-container">
<article{{ attributes }} id="fighter">
<div{{ content_attributes }}>
<div id="fighter__hero">
<div id="fighter__image">
<img src="{{ fighterImg }}"/>
</div>
<div id="fighter__text">
<h1>{{ node.field_first_name.value }} {{ node.field_last_name.value }}</h1>
<div id="fighter__record">
{{ node.field_wins.value }} - {{ node.field_losses.value }} - {{ node.field_ties.value }}
</div>
</div>
</div>
<div id="fighter__personal">
{% for datapoint, value in personal_info %}
<div class="data-wrapper">
<span class="label">{{ datapoint }}</span>
<div class="datapoint">
{{ value }}
</div>
</div>
{% endfor %}
</div>
<h2 id="stats-header">Fighter Stats</h2>
<div id="fighter__stats">
{% for datapoint, value in stats %}
<div class="data-wrapper">
<span class="label">{{ datapoint }}</span>
<div class="datapoint">
{{ value }}
</div>
</div>
{% endfor %}
</div>
</div>
</article>
</div>
</div>

View File

@@ -0,0 +1,14 @@
{{ attach_library('dchadwick/predict_event') }}
<header aria-label="Site header" class="header" id="header" role="banner">
{{ page.navigation }}
</header>
<section class="main" id="main">
<main aria-label="Site main content" class="content" id="content" role="main">
{{ page.content }}
</main>
</section>
<footer aria-label="Site footer" class="footer" id="footer" role="contentinfo">
<div class="footer--bottom">
{{ page.footer_bottom }}
</div>
</footer>

View File

@@ -1,9 +1,20 @@
{# attach_library('ufc/ufc_react') #}
<header aria-label="Site header" class="header" id="header" role="banner">
{{ page.navigation }}
</header>
<section class="main" id="main">
<main aria-label="Site main content" class="content" id="content" role="main">
{{ page.content }}
<div id="react-app"></div>
{#
{% include '@dchadwick/components/button.html.twig' with { 'type': 'danger', 'text': "WARNING!!!" } %}
{% include '@dchadwick/components/button.html.twig' with { 'type': 'primary', 'text': "Primary" } %}
{% include '@dchadwick/components/button.html.twig' with { 'type': 'secondary', 'text': "Secondary" } %}
#}
</main>
</section>
<footer aria-label="Site footer" class="footer" id="footer" role="contentinfo">