Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions js/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
43 changes: 43 additions & 0 deletions js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "saver-webui-fe",
"version": "0.0.1",
"description": "Saver's Web UI frontend",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build-prod": "webpack --config webpack.prod.js",
"build-dev": "webpack --config webpack.dev.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/drbig/saver.git"
},
"author": "Piotr S. Staszewski",
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/drbig/saver/issues"
},
"homepage": "https://github.com/drbig/saver#readme",
"dependencies": {
"babel-core": "^6.26.3",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.19",
"coffee-loader": "^0.9.0",
"coffeescript": "^2.3.1",
"css-loader": "^1.0.0",
"git-revision-webpack-plugin": "^3.0.3",
"handlebars": "^4.0.11",
"handlebars-loader": "^1.7.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.8.0",
"less-loader": "^4.1.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"style-loader": "^0.21.0",
"uglifyjs-webpack-plugin": "^1.2.7",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.11.1",
"webpack-merge": "^4.1.1"
}
}
108 changes: 108 additions & 0 deletions js/src/index.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
require './index.less'
import React from 'react'
import {render} from 'react-dom'


class Save extends React.Component
constructor: (props) ->
super props
this.state = {
isDetailed: false,
}

toggleDetailed: ->
this.setState((prevState) => {isDetailed: !prevState.isDetailed})

render: ->
<li>
<a className="knob">[del]</a>
<a className="saveMain">{this.props.save.Stamp}</a>
<span className="gameStamp">{this.props.save.Note}</span>
</li>


class Game extends React.Component
constructor: (props) ->
super props
this.state = {
isExpanded: false,
isDetailed: false,
}

toggleExpanded: ->
this.setState((prevState) => {isExpanded: !prevState.isExpanded})

toggleDetailed: ->
this.setState((prevState) => {isDetailed: !prevState.isDetailed})

render: ->
knob = if this.state.isExpanded
'[ - ]'
else
'[ + ]'

<li className="game">
<span className="knob">{knob}</span>
<a className="info" onClick={=> this.toggleDetailed()}>[i]</a>
<span className="savesCounter">({this.props.game.Saves.length})</span>
<a className="gameName" onClick={=> this.toggleExpanded()}>{this.props.game.Name}</a>
<span className="gameStamp">{this.props.game.Stamp}</span>
{if this.state.isDetailed
<div className="gameInfo">
Path: {this.props.game.Path}
Size: {this.props.game.Size}
</div>
}
{if this.state.isExpanded
<ol className="saves">
{this.props.game.Saves.map((save) => <Save key={save.Stamp} save={save} />)}
</ol>
}
</li>


class App extends React.Component
constructor: (props) ->
super props
this.state = {
isLoaded: false,
error: null,
cfg: {},
currentGame: null,
}

componentDidMount: ->
fetch('/api/list')
.then((response) => response.json())
.then(
(ok) =>
this.setState({
isLoaded: true,
cfg: ok,
})
,
(error) =>
this.setState({
isLoaded: true,
error: error,
})
)

render: ->
if this.state.error
<div className="error">Error: {this.state.error.message}</div>
else if !this.state.isLoaded
<div>Loading...</div>
else
<div>
Root: {this.state.cfg.Root}
{if this.state.cfg.Games.length < 1
<div className="Error">No games defined. Please use CLI.</div>
else
<ul className="games">
{this.state.cfg.Games.map((game) => <Game key={game.Name} game={game} />)}
</ul>
}
</div>

render <App />, document.getElementById('app')
15 changes: 15 additions & 0 deletions js/src/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ htmlWebpackPlugin.options.title }}</title>
</head>
<body>
<div id="app"></div>
<div class="footer">
urwcal {{ htmlWebpackPlugin.options.version }}
&copy; Piotr S. Staszewski 2018
<a href="https://github.com/drbig/saver">GitHub</a>
</div>
</body>
</html>
75 changes: 75 additions & 0 deletions js/src/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
body {
background: black;
color: white;
}

div.footer {
font-size: 0.7em;
padding-top: 1em;
}

div.error {
color: red;
}

div.gameInfo {
display: block;
font-size: 0.8em;
padding: 0.5em;
}

ol.saves {
display: block;
padding: 0.5em;
}

span {
display: inline-block;
}

a.gameName {
display: inline-block;
width: 32em;
}
a.gameName:hover {
color: yellow;
}

a.saveMain {
display: inline-block;
width: 35em;
}
a.saveMain:hover {
color: yellow;
}

span.gameStamp {
font-family: monospace;
font-size: 0.8em;
}

.knob {
font-family: monospace;
padding-right: 0.5em;
}

span.savesCounter {
font-family: monospace;
display: inline-block;
width: 2em;
text-align: center;
padding-right: 0.5em;
}

a.info {
font-family: monospace;
padding-right: 0.5em;
}
a.info:hover {
color: yellow;
}

li.saves {
display: block;
padding: 0.5em;
}
53 changes: 53 additions & 0 deletions js/webpack.common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const path = require('path');

const CleanWebpackPlugin = require('clean-webpack-plugin');
const GitRevisionPlugin = require('git-revision-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const gitRevisionPlugin = new GitRevisionPlugin({
versionCommand: 'describe --always'
});

module.exports = {
entry: {
app: './src/index.coffee'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
hash: true,
template: 'src/index.hbs',
title: 'Saver Web UI',
version: gitRevisionPlugin.version()
})
],
module: {
loaders: [
{
test: /\.hbs$/,
use: ['handlebars-loader']
},
{
test: /\.coffee$/,
use: [
{
loader: 'coffee-loader',
options: {
transpile: {
presets: ['env', 'react']
}
}
}
]
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
9 changes: 9 additions & 0 deletions js/webpack.dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const common = require('./webpack.common.js');
const merge = require('webpack-merge');

module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
});
10 changes: 10 additions & 0 deletions js/webpack.prod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const common = require('./webpack.common.js');
const merge = require('webpack-merge');

const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = merge(common, {
plugins: [
new UglifyJSPlugin()
]
});
10 changes: 9 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

const (
VERSION = `0.9.1`
VERSION = `0.9.1-webui`
timeFmt = `2006-01-02 15:04:05`
fileFmt = `2006-01-02_150405`
)
Expand All @@ -23,6 +23,7 @@ var build = `UNKNOWN` // injected in Makefile
var (
flagConfig string
flagVerbose bool
flagPort int
cfg *Config
idRange = regexp.MustCompile(`(\d+)-(\d+)`)
spinner = Spinner{}
Expand All @@ -47,6 +48,7 @@ Commands:
<name> [del]ete <id|from-to> - delete given save(s)
<name> [kill] - delete game and all saves
[migrate] - migrate config, if needed
[webui] - start the Web UI

Where:
name - arbitrary name used to identify a game/character/world etc.
Expand All @@ -58,6 +60,7 @@ Where:
}
flag.StringVar(&flagConfig, "c", "saver.json", "path to config file")
flag.BoolVar(&flagVerbose, "v", false, "be very verbose")
flag.IntVar(&flagPort, "p", 8888, "Web UI port")
}

func main() {
Expand Down Expand Up @@ -96,6 +99,11 @@ func main() {
err := cfg.Migrate()
dieOnErr("ERROR", err)
save = true
case "webui":
// start the Web UI
go startWebUI()
sigwait()
save = true
default:
// per-game commands
checkArgs(false, 2)
Expand Down
20 changes: 20 additions & 0 deletions sigwait_common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// See LICENSE.txt for licensing information.

package main

import (
"fmt"
"os"
"os/signal"
)

func _sigwait(sigs ...os.Signal) {
sig := make(chan os.Signal)
signal.Notify(sig, sigs...)
s := <-sig
if s == sigs[0] {
fmt.Println()
}
webuiLog.Printf("Signal '%s' received, stopping", s)
return
}
Loading