Nodification of app. #1
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
|
public/bundle.js
|
||||||
|
**/dist
|
||||||
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6513
package-lock.json
generated
Normal file
6513
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
public/css/styles.css
Normal file
36
public/css/styles.css
Normal file
@@ -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>
|
|
||||||
1
public/js/app-bundle.js
Normal file
1
public/js/app-bundle.js
Normal file
File diff suppressed because one or more lines are too long
23
src/back/app.js
Normal file
23
src/back/app.js
Normal file
@@ -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!');
|
||||||
|
});
|
||||||
43
src/back/nodes.json
Normal file
43
src/back/nodes.json
Normal file
@@ -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!"
|
||||||
|
}
|
||||||
|
]
|
||||||
20
src/back/views/home.mustache
Normal file
20
src/back/views/home.mustache
Normal file
@@ -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>
|
||||||
53
src/front/index.js
Normal file
53
src/front/index.js
Normal file
@@ -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]);
|
||||||
|
});
|
||||||
|
}
|
||||||
58
src/index.js
58
src/index.js
@@ -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]);
|
|
||||||
}
|
|
||||||
@@ -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