improve gamebook editor UI

This commit is contained in:
Thibault Duplessis 2017-08-22 09:22:51 -05:00
parent ca990d4b6c
commit 4510475440
7 changed files with 93 additions and 67 deletions

View file

@ -1,5 +1,7 @@
.gb_edit .lichess_game .lichess_ground {
margin-bottom: -517px;
margin-bottom: -409px;
}
.gb_edit .lichess_game .lichess_ground {
}
.gb_edit .gamebook_wrap {
height: 500px;
@ -11,7 +13,6 @@
}
.gb_edit .gamebook .deviation,
.gb_edit .gamebook .hint {
padding-top: 8px;
display: flex;
flex-flow: column;
}
@ -23,29 +24,43 @@
resize: vertical;
width: 100%;
box-sizing: border-box;
height: 8em;
height: 10em;
border-width: 1px 0;
padding: 5px;
}
.gb_edit .gamebook .hint textarea {
height: 5em;
height: 7em;
}
.gb_edit .gamebook .legend {
padding: 8px 10px;
display: flex;
border-bottom: 1px solid #ccc;
}
.gb_edit .gamebook .legend::before {
display: block;
float: left;
font-size: 2.5em;
margin: 2px 8px 0 0;
opacity: 0.5;
.gb_edit .gamebook .legend i {
flex: 0 0 50px;
font-size: 26px;
opacity: 0.7;
display: flex;
align-items: center;
justify-content: center;
}
.gb_edit .gamebook .todo {
border-left: 5px solid #dc322f!important;
.gb_edit .gamebook .legend.clickable:hover {
cursor: pointer;
background: #3893E8;
color: #fff;
}
.gb_edit .gamebook .done {
border-left: 5px solid #759900!important;
.gb_edit .gamebook .legend.clickable:hover i {
opacity: 0.9;
}
.gb_edit .gamebook .legend p {
flex: 1 1 100%;
padding: 8px 10px;
}
.gb_edit .gamebook .todo i {
background: #dc322f;
color: #fff;
}
.gb_edit .gamebook .done i {
background: #759900;
}
body.dark .gb_edit .gamebook {

View file

@ -793,6 +793,8 @@ export default class AnalyseCtrl {
return this.study && this.study.gamebookPlay();
}
isGamebook = (): boolean => !!(this.study && this.study.data.chapter.gamebook);
withCg<A>(f: (cg: ChessgroundApi) => A): A | undefined {
if (this.chessground && this.cgVersion.js === this.cgVersion.dom)
return f(this.chessground);

View file

@ -2,7 +2,7 @@ import { h } from 'snabbdom'
import { Hooks } from 'snabbdom/hooks'
import { VNode } from 'snabbdom/vnode'
import AnalyseCtrl from '../../ctrl';
import { bind } from '../../util';
import { bind, iconTag } from '../../util';
import { MaybeVNodes } from '../../interfaces';
import { throttle } from 'common';
@ -19,60 +19,63 @@ export function render(ctrl: AnalyseCtrl): VNode {
let content: MaybeVNodes;
function commentButton(text: string = 'comment') {
return h('a.button.thin', {
hook: bind('click', () => {
study.commentForm.open(study.vm.chapterId, ctrl.path, ctrl.node);
}, ctrl.redraw),
}, text);
}
const commentHook: Hooks = bind('click', () => {
study.commentForm.open(study.vm.chapterId, ctrl.path, ctrl.node);
}, ctrl.redraw);
if (!ctrl.path) {
if (isMyMove) content = [
h('div.legend.todo', { class: { done: isCommented } }, [
'Help the player find the initial move, with a ',
commentButton(),
'.'
h('div.legend.todo.clickable', {
hook: commentHook,
class: { done: isCommented }
}, [
iconTag('c'),
h('p', 'Help the player find the initial move, with a comment.')
]),
renderHint(ctrl)
];
else content = [
h('div.legend.todo', { class: { done: isCommented } }, [
'Introduce the gamebook with a ',
commentButton(),
', and put the opponent\'s first move on the board.'
])
h('div.legend.todo', { class: { done: isCommented } },
'Introduce the gamebook with a comment, and put the opponent\'s first move on the board.'
)
];
}
else if (ctrl.onMainline) {
if (isMyMove) content = [
h('div.legend.todo', { class: { done: isCommented } }, [
'Comment the opponent move, and help the player find the next move, with a ',
commentButton(),
'.'
h('div.legend.todo.clickable', {
hook: commentHook,
class: { done: isCommented }
}, [
iconTag('c'),
h('p', 'Explain the opponent move, and help the player find the next move, with a comment.')
]),
renderHint(ctrl)
];
else content = [
h('div.legend', [
'Reflect on the player\'s correct move, with a ',
commentButton(),
'; or leave empty to jump immediately to the next move.'
h('div.legend.clickable', {
hook: commentHook,
}, [
iconTag('c'),
h('p', 'Reflect on the player\'s correct move, with a comment; or leave empty to jump immediately to the next move.')
]),
hasVariation ? null : h('div.legend', [
iconTag('G'),
h('p', 'Add variation moves to explain why specific other moves are wrong.')
]),
hasVariation ? null : h('div.legend', {
attrs: { 'data-icon': '' }
}, 'Add variation moves to explain why specific other moves are wrong.'),
renderDeviation(ctrl)
];
}
else content = [
h('div.legend.todo', { class: { done: isCommented } }, [
'Explain why this move is wrong in a ',
commentButton(),
'.'
h('div.legend.todo.clickable', {
hook: commentHook,
class: { done: isCommented }
}, [
iconTag('c'),
h('p', 'Explain why this move is wrong in a comment')
]),
h('div.legend',
'Or promote it as the mainline if it is the right move.')
h('div.legend', [
h('p', 'Or promote it as the mainline if it is the right move.')
])
];
return h('div.gamebook_wrap', {
@ -84,11 +87,12 @@ export function render(ctrl: AnalyseCtrl): VNode {
function renderDeviation(ctrl: AnalyseCtrl): VNode {
const field = 'deviation';
return h('div.deviation.todo', { class: { done: nodeGamebookValue(ctrl.node, field).length > 2 } }, [
h('label', {
attrs: { for: 'gamebook-deviation' }
}, 'When any other wrong move is played:'),
h('textarea#gamebook-deviation', {
return h('div.deviation', [
h('div.legend.todo', { class: { done: nodeGamebookValue(ctrl.node, field).length > 2 } }, [
iconTag('c'),
h('p', 'When any other wrong move is played:')
]),
h('textarea', {
attrs: { placeholder: 'Explain why all other moves are wrong' },
hook: textareaHook(ctrl, field)
})
@ -98,10 +102,11 @@ function renderDeviation(ctrl: AnalyseCtrl): VNode {
function renderHint(ctrl: AnalyseCtrl): VNode {
const field = 'hint';
return h('div.hint', [
h('label', {
attrs: { for: 'gamebook-hint' }
}, 'Optional, on-demand hint for the player:'),
h('textarea#gamebook-hint', {
h('div.legend', [
iconTag(''),
h('p', 'Optional, on-demand hint for the player:')
]),
h('textarea', {
attrs: { placeholder: 'Give the player a tip so they can find the right move' },
hook: textareaHook(ctrl, field)
})

View file

@ -0,0 +1,3 @@
export type GamebookOverride = undefined | 'edit' | 'play' | 'analyse';

View file

@ -2,8 +2,9 @@ import { Prop } from 'common';
import { NotifCtrl } from './notif';
import { AnalyseData } from '../interfaces';
import { StudyPracticeCtrl } from './practice/interfaces';
import GamebookPlayCtrl from './gamebook/gamebookPlayCtrl';
import { ChapterDescriptionCtrl } from './chapterDescription';
import GamebookPlayCtrl from './gamebook/gamebookPlayCtrl';
import { GamebookOverride } from './gamebook/interfaces';
export interface StudyCtrl {
data: StudyData;
@ -61,8 +62,6 @@ export interface StudyVm {
gamebookOverride: GamebookOverride;
}
export type GamebookOverride = undefined | 'edit' | 'play' | 'analyse';
export interface StudyData {
id: string;
name: string;

View file

@ -13,7 +13,7 @@ import { ctrl as tagsCtrl } from './studyTags';
import * as tours from './studyTour';
import * as xhr from './studyXhr';
import { path as treePath } from 'tree';
import { StudyCtrl, StudyVm, Tab, TagTypes, StudyData, StudyChapterMeta, ReloadData, GamebookOverride } from './interfaces';
import { StudyCtrl, StudyVm, Tab, TagTypes, StudyData, StudyChapterMeta, ReloadData } from './interfaces';
import GamebookPlayCtrl from './gamebook/gamebookPlayCtrl';
import { ChapterDescriptionCtrl } from './chapterDescription';
@ -40,9 +40,11 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
sticky: sticked,
write: true
},
behind: 0, // how many events missed because sync=off
updatedAt: Date.now() - data.secondsSinceUpdate * 1000, // how stale is the study
gamebookOverride: undefined
// how many events missed because sync=off
behind: 0,
// how stale is the study
updatedAt: Date.now() - data.secondsSinceUpdate * 1000,
gamebookOverride: undefined
};
})();
@ -334,7 +336,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
for (let i in chapters)
if (chapters[i].id === currentId) return chapters[parseInt(i) + 1];
},
setGamebookOverride(o: GamebookOverride) {
setGamebookOverride(o) {
vm.gamebookOverride = o;
instanciateGamebookPlay();
vm.mode.write = o !== 'play';

View file

@ -197,7 +197,7 @@ function buttons(ctrl: AnalyseCtrl) {
active: ctrl.explorer.enabled()
}
}, [iconTag(']')]),
ctrl.ceval.possible && ctrl.ceval.allowed() ? h('button.hint--bottom', {
ctrl.ceval.possible && ctrl.ceval.allowed() && !ctrl.isGamebook() ? h('button.hint--bottom', {
attrs: {
'data-hint': 'Practice with computer',
'data-act': 'practice'