Nodification of app. #1
@@ -1 +1,3 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
|
public/bundle.js
|
||||||
|
**/dist
|
||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/src/back/app.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Generated
+6513
File diff suppressed because it is too large
Load Diff
+7
-1
@@ -4,15 +4,21 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack --watch",
|
"start-front": "webpack --watch",
|
||||||
|
"start-back": "node src/back/app.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.4",
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||||
"webpack": "^4.41.2",
|
"webpack": "^4.41.2",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.10",
|
||||||
"webpack-dev-server": "^3.9.0"
|
"webpack-dev-server": "^3.9.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"mustache-express": "^1.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
body {
|
||||||
|
background-color: #222;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice-btn {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid black;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice-btn:hover {
|
||||||
|
background-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choice-div {
|
||||||
|
border: 1px green solid;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-div {
|
||||||
|
border: 1px red solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
width: 500px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#history div {
|
||||||
|
width: 450px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
|
|
||||||
<title>Textual game</title>
|
|
||||||
<meta name="description" content="The HTML5 Herald">
|
|
||||||
<meta name="author" content="SitePoint">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/styles.css?v=1.0">
|
|
||||||
|
|
||||||
<style type="text/css">
|
|
||||||
.choice-btn {
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid black;
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choice-btn:hover {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 id="active-node"></h1>
|
|
||||||
<div id="choices"></div>
|
|
||||||
<script src="./bundle.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
|
|||||||
|
const mustacheExpress = require('mustache-express');
|
||||||
|
const express = require('express');
|
||||||
|
const nodes = require('./nodes.json');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
// Register '.mustache' extension with The Mustache Express
|
||||||
|
app.engine('mustache', mustacheExpress());
|
||||||
|
|
||||||
|
app.set('view engine', 'mustache');
|
||||||
|
app.set('views', __dirname + '/views');
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
app.get('/', (request, response) => {
|
||||||
|
response.render('home', { title: 'Textual game!' });
|
||||||
|
});
|
||||||
|
app.get('/nodes', (request, response) => {
|
||||||
|
response.setHeader('Content-Type', 'application/json');
|
||||||
|
response.end(JSON.stringify(nodes));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000, () => {
|
||||||
|
console.log('Example app listening on port 3000!');
|
||||||
|
});
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "node-1",
|
||||||
|
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"id": "choice-1",
|
||||||
|
"text": "Sed ut perspiciatis unde omnis.",
|
||||||
|
"nextNode": "node-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "choice-2",
|
||||||
|
"text": "Nemo enim ipsam voluptatem",
|
||||||
|
"nextNode": "node-exit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "choice-3",
|
||||||
|
"text": "Ut enim ad minima veniam",
|
||||||
|
"nextNode": "node-exit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-2",
|
||||||
|
"text": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"id": "choice-4",
|
||||||
|
"text": "Quis autem vel eum iure",
|
||||||
|
"nextNode": "node-exit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "choice-5",
|
||||||
|
"text": "At vero eos et accusamus",
|
||||||
|
"nextNode": "node-exit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-exit",
|
||||||
|
"text": "Game over!"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<title>Textual game</title>
|
||||||
|
<meta name="description" content="The HTML5 Herald">
|
||||||
|
<meta name="author" content="SitePoint">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
<div id="history"></div>
|
||||||
|
<div id="choices"></div>
|
||||||
|
</div>
|
||||||
|
<script src="js/app-bundle.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
let jsonContent = [];
|
||||||
|
|
||||||
|
function printChoices(node) {
|
||||||
|
if (node.choices) {
|
||||||
|
return node.choices.forEach(choice => {
|
||||||
|
const newBtn = document.createElement('button');
|
||||||
|
newBtn.onclick = () => selectChoice(choice.id);
|
||||||
|
newBtn.innerHTML = choice.text;
|
||||||
|
newBtn.classList.add('choice-btn');
|
||||||
|
document.getElementById('choices').appendChild(newBtn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectChoice(choiceId) {
|
||||||
|
console.log('Click on choice ', choiceId);
|
||||||
|
const allChoices = jsonContent.flatMap(node =>
|
||||||
|
!node.choices ? [] : node.choices
|
||||||
|
);
|
||||||
|
const selectedChoice = allChoices.find(choice => choice.id === choiceId);
|
||||||
|
const nextNode = jsonContent.find(node => node.id === selectedChoice.nextNode);
|
||||||
|
|
||||||
|
addChoiceToHistory(selectedChoice);
|
||||||
|
updateActiveNode(nextNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addChoiceToHistory(selectedChoice) {
|
||||||
|
const choiceDiv = document.createElement('div');
|
||||||
|
choiceDiv.innerHTML = selectedChoice.text;
|
||||||
|
choiceDiv.classList.add('choice-div');
|
||||||
|
document.getElementById('history').appendChild(choiceDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateActiveNode(node) {
|
||||||
|
const nodeDiv = document.createElement('div');
|
||||||
|
nodeDiv.innerHTML = node.text;
|
||||||
|
nodeDiv.classList.add('node-div');
|
||||||
|
document.getElementById('history').appendChild(nodeDiv);
|
||||||
|
|
||||||
|
document.getElementById('choices').innerHTML = '';
|
||||||
|
printChoices(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
fetch('/nodes', {
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
jsonContent = data;
|
||||||
|
updateActiveNode(jsonContent[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
const jsonContent = [{
|
|
||||||
id: 'node-1',
|
|
||||||
text: 'Node 1',
|
|
||||||
choices: [{
|
|
||||||
id: 'choice-1',
|
|
||||||
text: 'Choice 1',
|
|
||||||
nextNode: 'node-2'
|
|
||||||
}, {
|
|
||||||
id: 'choice-2',
|
|
||||||
text: 'Choice 2',
|
|
||||||
nextNode: 'node-exit'
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
id: 'node-2',
|
|
||||||
text: 'Node 2',
|
|
||||||
choices: [{
|
|
||||||
id: 'choice-3',
|
|
||||||
text: 'Choice 3',
|
|
||||||
nextNode: 'node-exit'
|
|
||||||
}, {
|
|
||||||
id: 'choice-4',
|
|
||||||
text: 'Choice 4',
|
|
||||||
nextNode: 'node-exit'
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
id: 'node-exit',
|
|
||||||
text: 'Game over!'
|
|
||||||
}];
|
|
||||||
|
|
||||||
function printChoices(node) {
|
|
||||||
return node.choices.forEach(choice => {
|
|
||||||
const newBtn = document.createElement('button');
|
|
||||||
newBtn.onclick = () => selectChoice(choice.id);
|
|
||||||
newBtn.innerHTML = choice.text;
|
|
||||||
newBtn.classList.add('choice-btn');
|
|
||||||
document.getElementById('choices').appendChild(newBtn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectChoice(choiceId) {
|
|
||||||
console.log('Click on choice ', choiceId);
|
|
||||||
const allChoices = jsonContent.flatMap(node =>
|
|
||||||
!node.choices ? [] : node.choices
|
|
||||||
);
|
|
||||||
const selectedChoice = allChoices.find(choice => choice.id === choiceId);
|
|
||||||
const nextNode = jsonContent.find(node => node.id === selectedChoice.nextNode);
|
|
||||||
updateActiveNode(nextNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateActiveNode(node) {
|
|
||||||
document.getElementById('active-node').innerHTML = node.text;
|
|
||||||
document.getElementById('choices').innerHTML = '';
|
|
||||||
printChoices(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = () => {
|
|
||||||
updateActiveNode(jsonContent[0]);
|
|
||||||
}
|
|
||||||
+8
-10
@@ -2,15 +2,16 @@ const webpack = require("webpack");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
|
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
let config = {
|
entry: {
|
||||||
entry: "./src/index.js",
|
app: "./src/front/index.js",
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "./public"),
|
path: path.resolve(__dirname, "./public/js"),
|
||||||
filename: "./bundle.js"
|
filename: "[name]-bundle.js"
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
contentBase: path.resolve(__dirname, "./public"),
|
contentBase: path.resolve(__dirname, "./public/js"),
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
open: true,
|
open: true,
|
||||||
@@ -21,7 +22,4 @@ let config = {
|
|||||||
new webpack.SourceMapDevToolPlugin({})
|
new webpack.SourceMapDevToolPlugin({})
|
||||||
],
|
],
|
||||||
devtool: "eval-source-map"
|
devtool: "eval-source-map"
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
Reference in New Issue
Block a user