habitica/views/app/index.html

612 lines
27 KiB
HTML

<!-- $table-of-contents
===================================
do a find for the string after "→"
-----------------------------------
→ $modal-template
→ $customizations-modal
→ $avatar-template
=================================== -->
<Title:>
HabitRPG | Gamify Your Life
<Head:>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<modalDialogs:>
{#if _loggedIn}
<app:myModal modalId="settings-modal" header="Settings">
<h4>API</h4>
<small>Copy these for use in third party applications.</small>
<h6>User ID</h6>
<pre class=prettyprint>{_user.id}</pre>
<h6>API Token</h6>
<pre class=prettyprint>{_user.apiToken}</pre>
<hr/>
<a class='btn btn-danger' data-target="#reset-modal" data-toggle="modal">Reset</a>
<@footer>
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</@footer>
</app:myModal>
<app:myModal modalId="reset-modal" header="Reset">
<p>This resets your entire account - your tasks will be deleted and your character will start over.</p>
<p>This is highly discouraged because you'll lose historical data, which is useful for graphing your progress over time. However, some people find it useful in the beginning after playing with the app for a while.</p>
<@footer>
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<button data-dismiss="modal" x-bind=click:reset class="btn btn-danger btn-large">Reset</button>
</@footer>
</app:myModal>
<app:myModal modalId="why-ads-modal" header="Why Ads?">
<p>Habit is maintained by one dude: <a href="https://github.com/lefnire">Tyler</a>. Until Habit can make money, I need to stay afloat to fix bugs and add features. Consider it a donation :D</p>
<p>If ads make you sick, chime in on Habit's open <a href="https://github.com/lefnire/habitrpg/wiki/Business-Model">business model discussion</a></p>
<@footer>
<button data-dismiss="modal" class="btn btn-success">Ok</button>
</@footer>
</app:myModal>
<app:myModal modalId="party-modal">
{#if _user.party.current}
<h2>{_party.name}</h2>
<table class="table table-striped">
{#each _partyMembers as :member}
<tr><td>{username(:member.auth)}</td><td>({:member.id})</td></tr>
{/}
</table>
<form class=form-inline x-bind="submit: partyInvite">
{#if _view.partyError}
<div class='alert alert-danger'>{_view.partyError}</div>
{/}
<div class='control-group'>
<input type="text" class="input-medium" placeholder="User Id" value="{_newPartyMember}">
<input type="submit" class="btn" value="Invite" />
</div>
</form>
<a class='btn btn-danger' x-bind="click: partyLeave">Leave</a>
{else if _user.party.invitation}
<!-- TODO show by whom -->
<h2>You're Invited To {_party.name}</h2>
<a class='btn btn-success' x-bind="click: partyAccept">Accept</a>
<a class='btn btn-danger' x-bind="click: partyReject">Reject</a>
{else}
<h2>Create A Party</h2>
<!-- Not in a party , no invites - create a new one -->
<form class=form-inline x-bind="submit: partyCreate">
{#if _view.partyError}
<div class='alert alert-danger'>{_view.partyError}</div>
{/}
<div class=control-group>
<input type="text" class="input-medium" placeholder="Party Name" value="{_newParty}">
<input type="submit" class="btn" value="Create" />
</div>
<form>
{/}
</app:myModal>
{else}
<app:myModal modalId="login-modal" header="Login / Register">
<a href="/auth/facebook"><img src='/img/facebook-login-register.jpeg' alt="Login / Register With Facebook"/></a>
<h3>Or</h3>
<ul class="nav nav-tabs">
<li class="active"><a href="#" data-toggle="tab" data-target="#login">Login</a></li>
<li><a href="#" data-toggle="tab" data-target="#register">Register</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="login"><derby-auth:login /></div>
<div class="tab-pane" id="register"><derby-auth:register /></div>
</div>
</app:myModal>
{/}
<!-- Game Over Modal -->
<div style="{#unless equal(_user.stats.lvl,0)}display:none;{/}">
<app:myModal noDismiss=true modalId='dead-modal'>
<figure class="notification-character">
<img src="/img/BrowserQuest/habitrpg_mods/dead.png">
</figure>
<h3 class="notification-message">You died! Game Over.</h3>
<a x-bind=click:revive class="btn btn-danger btn-large notification-action">Continue</a>
</app:myModal>
</div>
<!-- Re-Roll modal -->
<app:myModal modalId='reroll-modal' header="Reset Your Tasks">
<app:userTokens/>
<p>Highly discouraged because red tasks provide good incentive to improve (<a target="_blank" href="https://github.com/lefnire/habitrpg#all-my-tasks-are-red-im-dying-too-fast">read more</a>). However, this becomes necessary after long bouts of bad habits.</p>
<@footer>
{#if lt(_user.balance,1)}
<a data-dismiss="modal" x-bind="click:showStripe" class="btn btn-danger btn-large">Buy More Tokens</a><span class='token-cost'>Not enough tokens</span>
{else}
<a data-dismiss="modal" x-bind=click:buyReroll class="btn btn-danger btn-large">Re-Roll</a><span class='token-cost'>4 Tokens</span>
{/}
</@footer>
</app:myModal>
<!-- $customizations-modal -->
<app:myModal modalId="customizations-modal" header="Customize">
{#with _user.preferences}
<!-- user avatar preview -->
<figure class="avatar-window">
<app:avatar profile={_user} />
<figcaption class="char-name">{username(_user.auth)}</figcaption>
</figure>
<!-- customization options -->
<menu type="list">
<!-- gender -->
<li class="customize-menu">
<menu label="Gender">
<button type="button" class="m_head_0 customize-option" data-value="m" x-bind="click:customizeGender"></button>
<button type="button" class="f_head_0 customize-option" data-value="f" x-bind="click:customizeGender"></button>
</menu>
</li>
<!-- hair -->
<li class="customize-menu">
<menu label="Hair">
<button type="button" class="{.gender}_hair_blond customize-option" data-value="blond" x-bind="click:customizeHair"></button>
<button type="button" class="{.gender}_hair_black customize-option" data-value="black" x-bind="click:customizeHair"></button>
<button type="button" class="{.gender}_hair_brown customize-option" data-value="brown" x-bind="click:customizeHair"></button>
<button type="button" class="{.gender}_hair_white customize-option" data-value="white" x-bind="click:customizeHair"></button>
</menu>
</li>
<!-- skin -->
<li class="customize-menu">
<menu label="Skin">
<button type="button" class='{.gender}_skin_dead customize-option' data-value="dead" x-bind="click:customizeSkin"></button>
<button type="button" class='{.gender}_skin_orc customize-option' data-value="orc" x-bind="click:customizeSkin"></button>
<button type="button" class='{.gender}_skin_asian customize-option' data-value="asian" x-bind="click:customizeSkin"></button>
<button type="button" class='{.gender}_skin_black customize-option' data-value="black" x-bind="click:customizeSkin"></button>
<button type="button" class='{.gender}_skin_white customize-option' data-value="white" x-bind="click:customizeSkin"></button>
</menu>
</li>
</menu>
{#if equal(_user.preferences.gender, 'f')} <!-- Sorry boys -->
<menu type="list">
<li class="customize-menu">
<menu label="Clothing">
<button type="button" class="f_armor_0_v1 customize-option" data-value="v1" x-bind="click:customizeArmorSet"></button>
<button type="button" class="f_armor_0_v2 customize-option" data-value="v2" x-bind="click:customizeArmorSet"></button>
</menu>
</li>
</menu>
{/}
{/}
<@footer>
<button data-dismiss="modal" class="btn btn-success">Ok</button>
</@footer>
</app:myModal>
<alerts:>
{#if _flash.error}
<ul class="alert alert-error">
{#each _flash.error as :error}<li>{:error}</li>{/}
</ul>
{/}
{#if equal(_user.flags.kickstarter,'show')}
<div class='alert alert-success'>
<a x-bind="click:closeKickstarterNofitication" class='pull-right'>Dismiss</a>
Help Habit by backing the <strong><a href="http://kck.st/XoA3Yg">Kickstarter</a></strong>! Funds iPhone & Android apps, <a href="https://github.com/lefnire/habitrpg/issues?labels=critical&page=1&state=open">bug fixes</a>, and the <a href="https://github.com/lefnire/habitrpg/issues/58">Groups feature</a>.
</div>
{/}
<Header:>
<app:modalDialogs />
<ui:connectionAlert>
<div id="head" class="container-fluid">
<!-- options menu -->
<div class='pull-right'>
{#unless _loggedIn}
<a href="#" class="btn btn-small btn-info" data-target="#login-modal" data-toggle="modal">Login / Register</a>
{else}
<div class="btn-group">
<button class="btn btn-small">
{#if _user.party.invitation}<span class="badge badge-success">1</span>{/}
{username(_user.auth)}
</button>
<button class="btn btn-small dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-target="#settings-modal" data-toggle="modal">Settings</a></li>
{#if _user.flags.partyEnabled}
<li><a href="#" data-target="#party-modal" data-toggle="modal">
Party{#if _user.party.invitation}<span class="badge badge-success">1</span>{/}
</a></li>
{/}
<li><a href='/logout'>Logout</a></li>
</ul>
</div>
{/}
</div>
<!-- main header -->
<div class="row-fluid">
<div class='char-status {#if gt(_partyMembers.length,1)}span8 offset2 has-party{else}span6 offset3{/}'>
<!-- avatar -->
<figure class="main-avatar-wrap">
<app:avatar profile={_user} main="true" />
</figure>
<!-- party -->
{#each _partyMembers as :member}
{#unless equal(:member.id, _userId)}
<figure class="party-avatar-wrap" rel="tooltip" title="{username(:member.auth)}" data-placement="bottom">
<app:avatar profile={:member} party="true" />
</figure>
{/}
{/}
<!-- progress bars -->
<div class="progress-bars">
<div class="progress progress-danger" rel=tooltip data-placement=bottom title="Health">
<div class="bar" style="width: {percent(_user.stats.hp, 50)}%;"></div>
<span class="progress-text"><i class=icon-heart></i> {round(_user.stats.hp)} / 50</span>
</div>
<div class="progress progress-warning" rel=tooltip data-placement=bottom title="Experience">
<div class="bar" style="width: {percent(_user.stats.exp,_tnl)}%;"></div>
<span class="progress-text">
{#if _user.history.exp}
<a x-bind=click:toggleChart data-toggle-id="exp-chart" data-history-path="_user.history.exp" rel=tooltip title="Progress"><i class=icon-signal></i></a>&nbsp;
{/}
<i class=icon-star></i> {round(_user.stats.exp)} / {_tnl}
</span>
</div>
<div id="exp-chart" style="display:none;"></div>
</div>
<!-- end .char-status -->
</div>
<!-- end .row-fluid -->
</div>
<!-- end #head -->
</div>
<Body:>
<br/>
<div id=wrap class=container-fluid>
<app:alerts />
<div id=main class=row-fluid>
<!-- would rather have one component: <app:taskList>, which handles taskList, task, and newTask. However,
can't pass references as paramters. so <app:taskList newModel={_newHabit} list={_habitList}> doesn't work
and have to pass those in via {{{content}}} instead -->
<!--helpTitle & helpContent moved to tour -->
<div class="span3 well habits">
<h2>Habits</h2>
<!--removing for now, help-info in the tour instead-->
<!--<span class="help-icon" rel="popover" data-placement="bottom" data-trigger="hover" data-original-title="{{{helpTitle}}}" data-content="{{{helpContent}}}"><i class="icon-question-sign"></i></span>-->
<ul class='habits'>{#each _habitList as :task}<app:task />{/}</ul>
<app:newTask type=habit><input value={_newHabit} type="text" name=new-task placeholder="New Habit"/></app:newTask>
</div>
<div class="span3 well dailys">
<h2>Daily</h2>
<ul class='dailys'>{#each _dailyList as :task}<app:task />{/}</ul>
<app:newTask type=daily><input value={_newDaily} type="text" name=new-task placeholder="New Daily"/></app:newTask>
</div>
<div class="span3 well todos">
<div class="tabbable"> <!-- Only required for left/right tabs -->
<div class="row-fluid">
<h2 class="span6">Todos</h2>
<ul class="span6 nav nav-pills">
<li class="active"><a href="#" data-target="#tab1" data-toggle="tab">Remaining</a></li>
<li><a href="#" data-target="#tab2" data-toggle="tab">Complete</a></li>
</ul>
</div>
<div class="tab-content">
<div class="tab-pane active" id="tab1">
<ul class='todos'>
{#each _todoList as :task}
{#if not(:task.completed)}
<app:task />
{/}
{/}
</ul>
<app:newTask type=todo><input value={_newTodo} type="text" name=new-task placeholder="New Todo"/></app:newTask>
</div>
<div class="tab-pane" id="tab2">
<ul class='completeds'>
{#each _todoList as :task}
{#if :task.completed}
<app:task />
{/}
{/}
</ul>
<a x-bind=click:clearCompleted>Clear Completed</a>
</div>
</div>
</div>
{#if _user.history.todos}
<a x-bind=click:toggleChart data-toggle-id="todos-chart" data-history-path="_user.history.todos" rel=tooltip title="Progress"><i class=icon-signal></i></a>
<div id="todos-chart" style="display:none;"></div>
{/}
</div>
<div class="span3 well rewards">
<!--Title -->
<div class="row-fluid">
<div class="span6"><h2>Rewards</h2></div>
<div class="span6">
<table><tr>
<td>{gold(_user.stats.gp)} </td>
<td><div class='shop_gold' rel='tooltip' title='Gold'></div></td>
<td>{silver(_user.stats.gp)} </td>
<td><div class='shop_silver' rel='tooltip' title='Silver'></div></td>
<!--<td>{copper(_user.stats.gp)} </td>
<td><div class='shop_copper' rel='tooltip' title='shop_copper'></div></td>-->
</tr></table>
</div>
</div>
<!-- Content -->
<ul class='rewards'>
{#each _rewardList as :task}<app:task />{/}
</ul>
{#if _user.flags.itemsEnabled}
<ul class='items'>
{#with _view.items.weapon as :item}<app:item />{/}
{#with _view.items.armor as :item}<app:item />{/}
{#with _view.items.head as :item}<app:item />{/}
{#with _view.items.shield as :item}<app:item />{/}
{#with _view.items.potion as :item}<app:item />{/}
{#with _view.items.reroll as :item}<app:item reroll=true />{/}
</ul>
{/}
<app:newTask type=reward><input value={_newReward} type="text" name=new-task placeholder="New Reward"/></app:newTask>
</div>
</div>
</div>
<!-- Footer -->
<footer class=footer>
<div class=container>
{#unless equal(_view.nodeEnv, 'production')}
<div class='pull-right'>
<button class='btn' x-bind="click:emulateNextDay">Emulate Next Day</button>
<button class='btn' x-bind="click:cheat">Add GP & Exp</button>
</div>
{/}
<div>
<ul>
<li>Copyright &copy; 2012 OCDevel LLC</li>
<li><a href="/splash.html">About</a></li>
<li><a target="_blank" href="http://habitrpg.tumblr.com/">Blog</a></li>
<li><a target="_blank" href="https://github.com/lefnire/habitrpg/issues?state=open">Bugs</a></li>
<li><a target="_blank" href="https://trello.com/board/habitrpg/50e5d3684fe3a7266b0036d6">Features</a></li>
<li><a target="_blank" href="https://github.com/lefnire/habitrpg/wiki/FAQ">FAQ</a></li>
<li><a target="_blank" href="https://github.com/lefnire/habitrpg/wiki/API">API</a></li>
<li><a target="_blank" href="https://github.com/lefnire/habitrpg#contact">Contact</a></li>
<li><a href="/privacy">Privacy</a></li>
<li><a href="/terms">Terms</a></li>
</ul>
</div>
</div>
</footer>
<!-- $modal-template -->
<myModal: nonvoid>
{{#if @noDismiss}}<div data-action="backdrop" class="modal-backdrop"></div>{{/}}
<div class="modal {{#unless @noDismiss}}hide{{/}}" id={{@modalId}} role="dialog">
{{#if @header}}
<div class="modal-header">
{{#unless @noDismiss}}<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>{{/}}
<h3>{{unescaped @header}}</h3>
</div>
{{/}}
<div class="modal-body">{@content}</div>
{{#if @footer}}
<div class="modal-footer">{{@footer}}</div>
{{/}}
</div>
<userTokens:>
<div class="pull-right">
<div class="input-append">
<span class="uneditable-input" style="width:auto;">{tokens(_user.balance)}</span>
<span class="add-on">Tokens</span>
</div>
<a class="label" data-toggle="modal" href='#reset-modal'><i class="icon-ban-circle"></i>Reset</a>
</div>
<!--<span class="well pull-right">Tokens: {tokens(_user.balance)}</span>-->
<newTask: nonvoid>
<form class="form-inline new-task-form" id=new-{{@type}} data-task-type={{@type}} x-bind=submit:addTask>
{{@content}}
<input class="btn" type=submit value=Add>
</form>
{#if _loggedIn}
{#unless equal(@type,'reward')}
{#unless equal(_user.flags.ads,'hide')}
<span class='pull-right'>
<a x-bind="click:showStripe" rel='tooltip' title='Remove Ads'><i class='icon-remove'></i></a><br/>
<a href="#" data-target="#why-ads-modal" data-toggle="modal" rel='tooltip' title='Why Ads?'><i class='icon-question-sign'></i></a>
</span>
<script type="text/javascript" x-no-minify><!--
google_ad_client = "ca-pub-3242350243827794";
/* Test */
google_ad_slot = "5883123375";
google_ad_width = 234;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="https://pagead2.googlesyndication.com/pagead/show_ads.js" x-no-minify>
</script>
{/}
{/}
{/}
<task:>
<li data-id={{:task.id}} class="task {taskClasses(:task.type, :task.completed, :task.value, :task.repeat)}">
<pre>
<div class="task-meta-controls">
<div class="hover-show">
<a x-bind=click:toggleTaskEdit data-hide-id="{{:task.id}}-chart" data-toggle-id="{{:task.id}}-edit" rel=tooltip title="Edit"><i class="icon-pencil"></i></a>
<a x-bind=click:del rel=tooltip title="Delete"><i class="icon-trash"></i></a>
{#if :task.history}
<a x-bind=click:toggleChart data-toggle-id="{{:task.id}}-chart" data-hide-id="{{:task.id}}-edit" data-history-path="_user.tasks.{{:task.id}}.history" rel="tooltip" title="Progress">
<i class="icon-signal"></i>
</a>
{/}
</div>
{#if :task.notes}
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:task.notes}" data-original-title="{:task.text}" class='task-notes'><i class="icon-comment"></i></span>
{/}
</div>
<div class="task-controls">
<!-- Habits -->
{#if equal(:task.type, 'habit')}
{#if :task.up}<a data-direction=up x-bind=click:score><img src="/img/add.png" /></a>{/}
{#if :task.down}<a data-direction=down x-bind=click:score><img src="/img/remove.png" /></a>{/}
<!-- Rewards -->
{else if equal(:task.type, 'reward')}
<a x-bind=click:score class="buy-link" data-direction=down>{:task.value}<img src="/img/coin_single_gold.png"/></a>
<!-- Daily & Todos -->
{else}
<input type=checkbox checked="{:task.completed}"/>
{/}
</div>
<div class="task-text">{:task.text}</div>
<app:taskMeta />
</pre>
</li>
<taskMeta:>
<div style="display:none;" id={{:task.id}}-edit>
<hr/>
<form x-bind=submit:toggleTaskEdit data-toggle-id="{{:task.id}}-edit">
<div class=control-group>
<label>Text</label><input type=text value={:task.text} />
<label>Notes</label><textarea rows=3>{:task.notes}</textarea>
</div>
{#if equal(:task.type, 'habit')}
<div class="control-group">
<label class="checkbox inline"><input type=checkbox checked={:task.up}>Up</label>
<label class="checkbox inline"><input type=checkbox checked={:task.down}>Down</label>
</div>
{/}
{#if equal(:task.type, 'daily')}
<label>Repeat</label>
<div class="control-group btn-group repeat-days">
<!-- note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding -->
<button type="button" class="btn btn-info {#if :task.repeat.su}active{/}" data-day='su' x-bind=click:toggleDay>Su</button>
<button type="button" class="btn btn-info {#if :task.repeat.m}active{/}" data-day='m' x-bind=click:toggleDay>M</button>
<button type="button" class="btn btn-info {#if :task.repeat.t}active{/}" data-day='t' x-bind=click:toggleDay>T</button>
<button type="button" class="btn btn-info {#if :task.repeat.w}active{/}" data-day='w' x-bind=click:toggleDay>W</button>
<button type="button" class="btn btn-info {#if :task.repeat.th}active{/}" data-day='th' x-bind=click:toggleDay>Th</button>
<button type="button" class="btn btn-info {#if :task.repeat.f}active{/}" data-day='f' x-bind=click:toggleDay>F</button>
<button type="button" class="btn btn-info {#if :task.repeat.s}active{/}" data-day='s' x-bind=click:toggleDay>S</button>
</div>
{/}
{#if equal(:task.type, 'reward')}
<div class=control-group>
<label>Price
<div class="input-append">
<input class="span5" size="16" type="number" min="0" value={:task.value}><span class="add-on">Gold</span>
</div>
</label>
</div>
{/}
<button type=submit class="btn">Save & Close</button>
</form>
</div>
<div style="display:none;" id={{:task.id}}-chart></div>
<item:>
{#unless :item.hide}
<li class="task reward item">
<pre>
<div class="task-meta-controls">
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:item.notes}" data-original-title="{:item.text}" class='task-notes'><i class="icon-comment"></i></span>
</div>
<div class="task-controls">
{#if @reroll}
<a href="#" data-toggle="modal" data-target="#reroll-modal" class="item-buy-link" style='cursor:pointer'><i class=icon-retweet></i></a>
{else}
<a x-bind=click:buyItem class="item-buy-link" data-type={:item.type} data-value={:item.value} data-index={:item.index}>{:item.value}<img src="/img/coin_single_gold.png"/></a>
{/}
</div>
<div class="task-text">
{#if :item.icon}
<img src="/img/BrowserQuest/habitrpg_mods/{:item.icon}" /> {:item.text}
{else}
<table class='shop-table'><tr>
<td><div class="shop_{:item.classes} shop-sprite"></div></td>
<td>{:item.text}</td>
</tr></table>
{/}
</div>
</pre>
</li>
{/}
<!-- $avatar-template -->
<avatar:>
<div class="avatar {{#if @main}}main-avatar{{/}} {{#if @party}}party-avatar{{/}}" data-toggle='{{#if @main}}modal{{/}}' data-target='{{#if @main}}#customizations-modal{{/}}'>
<div class='character-sprites'>
{#with @profile.preferences as :p}
<span class='{:p.gender}_skin_{:p.skin}'></span>
<span class='{:p.gender}_hair_{:p.hair}'></span>
<span class="{equipped(@profile, 'armor')}"></span>
<span class="{equipped(@profile, 'head')}"></span>
<span class='{:p.gender}_shield_{@profile.items.shield}'></span>
<span class='{:p.gender}_weapon_{@profile.items.weapon}'></span>
{/}
</div>
{{#if @main}}
<div class="lvl"><span class="badge badge-info">Lvl {@profile.stats.lvl}</span></div>
{{else if @party}}
<div class="lvl"><span class="badge badge-info">Lvl {@profile.stats.lvl}</span></div>
{{/}}
</div>
<Scripts:>
<script src="https://checkout.stripe.com/v2/checkout.js"></script>
{#if equal(_view.nodeEnv,"production")}
<!-- Google Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-33510635-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
{/}