This commit is contained in:
Tim 2014-10-24 11:30:45 +02:00
Родитель f7b21a27fe 4a4bea940b
Коммит 4d34c8a5cc
71 изменённых файлов: 377 добавлений и 1347 удалений

Просмотреть файл

@ -1,4 +1,4 @@
<a class="cell" data-id="{{id}}" href="/make/{{id}}/play">
<a class="cell" data-id="{{id}}" href="/make/{{id}}/{{mode || 'play'}}">
<div class="left">
<span class="title">{{name}}</span>
<span v-if="author" class="description" v-bind-html="'by _'" v-with="{name: author.username|| guestKey}"></span>

Просмотреть файл

@ -3,6 +3,7 @@ var i18n = require('../../lib/i18n');
module.exports = {
className: 'app-cell',
template: require('./index.html'),
paramAttributes: ['mode'],
computed: {
guestKey: function() {
return i18n.get('Guest');

Просмотреть файл

@ -1,4 +1,5 @@
.app-cell .cell {
display: flex;
.app-icon,
.author-icon {
width: 50px;
@ -10,4 +11,14 @@
.app-icon {
border-radius: 50%;
}
.title {
.text-truncate;
}
.left, .right {
float: none;
width: auto;
}
.left {
flex-grow: 1;
}
}

Просмотреть файл

@ -1,6 +1,11 @@
<button class="back" v-if="back" v-on="click: goBack">&lt;</button>
<button v-if="back === true" class="back" v-on="click: goBack">&lt;</button>
<a v-if="typeof back === 'string'" class="back" href="{{back}}">&lt;</a>
<button v-if="cancel === true" v-on="click: goBack">{{'Cancel' | i18n}}</button>
<a v-if="typeof cancel === 'string'" href="{{cancel}}">{{'Cancel' | i18n}}</a>
<h1>{{title | i18n}}</h1>
<button v-if="typeof onDone === 'function'" v-on="click: onDone">{{'Done' | i18n}}</button>
<a v-if="typeof onDone === 'string'" href="{{onDone}}">{{'Done' | i18n}}</a>
<button v-if="typeof onDone === 'function'" v-on="click: onDone" v-class="disabled: doneDisabled">{{doneLabel || 'Done' | i18n}}
</button>
<a v-if="typeof onDone === 'string'" href="{{onDone}}" v-class="disabled: doneDisabled">{{doneLabel || 'Done' | i18n}}</a>

Просмотреть файл

@ -41,6 +41,7 @@
right: 0;
}
&.back {
line-height: @header-height;
padding-top: 0;
font-size: 1.4em;
}

Просмотреть файл

@ -5,10 +5,10 @@
<p class="text-small">Make your own app at</p>
<p><a href="http://webmaker-app.mofodev.net" class="btn btn-dark btn-block">Mozilla Webmaker</a></p>
<!-- Can't show these until we have manifest + discover implemented -->
<!-- <ul class="list-btns">
<li><a class="btn" href="">Add to Homescreen</a></li>
<li><a class="btn" href="">Learn more abut this app</a></li>
<li><a class="btn" href="">Share App</a></li>
</ul> -->
<ul class="list-btns">
<li v-if="showInstall"><a class="btn" href="#" v-on="click: install">Add to Homescreen</a></li>
<!-- <li><a class="btn" href="">Learn more abut this app</a></li>
<li><a class="btn" href="">Share App</a></li> -->
</ul>
</div>
</div>

Просмотреть файл

@ -2,7 +2,8 @@ module.exports = {
id: 'publish-footer',
template: require('./index.html'),
data: {
showFooter: false
showFooter: false,
showInstall: false
},
methods: {
toggleShowFooter: function (e) {
@ -24,6 +25,29 @@ module.exports = {
self.toggleShowFooter();
}, false);
if (navigator.mozApps) {
var manifestUrl = location.href + 'manifest.webapp';
self.$data.install = function install(e) {
e.preventDefault();
var installLocFind = navigator.mozApps.install(manifestUrl);
installLocFind.onsuccess = function (data) {
self.$data.showInstall = false;
};
installLocFind.onerror = function() {
alert('Sorry, we could not install this app: ' + installLocFind.error.name);
};
};
var installCheck = navigator.mozApps.checkInstalled(manifestUrl);
installCheck.onsuccess = function() {
if (installCheck.result) {
self.$data.showInstall = false;
} else {
self.$data.showInstall = true;
}
};
}
self.toggleOverlay = function (show) {
if (show) {
overlay.classList.add('on');

Просмотреть файл

@ -39,7 +39,7 @@
margin-top: -25px;
width: 65px;
height: 65px;
margin-right: 17px;
margin-right: 4px;
}
#tabBar li g {

Просмотреть файл

@ -1,4 +1,4 @@
<a class="cell" data-id="{{id}}" href="/make/{{id}}/play">
<a class="cell" data-id="{{id}}" href="/make/{{id}}/edit">
<img class="app-icon" src="{{icon}}">
<div class="name">{{name | i18n}}</div>
</a>

Просмотреть файл

@ -1,6 +1,9 @@
var Blocks = require('./blocks');
var utils = require('./utils');
var uuid = require('./uuid');
var clone = require('clone');
var templates = require('./templates.json');
var i18n = require('./i18n');
var model = require('./model')();
var blocks = new Blocks();
@ -18,6 +21,32 @@ function App (id) {
self.data = model.data.apps[self.index];
}
// Global Methods
// createApp(options)
// - template: id of a template. Will overwrite options.data
// - data: a set of app data to clone
// - name: a name for the clone.
App.createApp = function (options) {
options = options || {};
if (options.template) {
options.data = templates[utils.findInArray(templates, 'id', options.template)];
}
if (!options.data) return;
var app = clone(options.data);
// Prepare the clone for use
app.id = uuid();
app.name = options.name || i18n.get('Untitled App');
app.author = model.data.user;
// Add to model & redirect to editor
model.data.apps.unshift(app);
return new App(app.id);
};
// Instance Methods
App.prototype.insert = function (blockId) {
var self = this;
var block = newBlock(blockId);

Просмотреть файл

@ -13,6 +13,12 @@ auth.on('newuser', function (assertion, email) {
auth._email = email;
});
auth.on('logout', function () {
auth._assertion = null;
auth._email = null;
});
auth.on('error', function (err) {
console.log(err);
});

7
lib/fake-discovery.js Normal file
Просмотреть файл

@ -0,0 +1,7 @@
var clone = require('clone');
var json = clone(require('./templates.json'));
module.exports = {
featured: json.splice(1, 5),
nearby: json.splice(5)
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -16,7 +16,10 @@ module.exports = function (id, username, cb) {
'Content-Type': 'application/json'
}
}, function (err, resp, body) {
if (err) return cb(err);
if (err) return cb({
status: resp.statusCode,
message: body
});
if (!body) return cb('There was no response');
cb(null, JSON.parse(body));
});

Просмотреть файл

@ -4,7 +4,7 @@
"name": "From Scratch",
"icon": "/images/placeholder_blank.png",
"author": {
"name": "",
"username": "",
"location": "",
"avatar": ""
},
@ -15,7 +15,7 @@
"name": "Journalist",
"icon": "/images/placeholder_journalist.png",
"author": {
"name": "Rafid Daoud",
"username": "Rafid Daoud",
"location": "",
"avatar": ""
},
@ -172,7 +172,7 @@
"name": "Vendor",
"icon": "/images/placeholder_vendor.png",
"author": {
"name": "Yousuf",
"username": "Yousuf",
"location": "",
"avatar": "/images/avatar_vendor.png"
},
@ -297,7 +297,7 @@
"name": "Medic",
"icon": "/images/placeholder_medic.png",
"author": {
"name": "Aya",
"username": "Aya",
"location": "",
"avatar": "/images/avatar_medic.png"
},
@ -308,7 +308,7 @@
"name": "Teacher",
"icon": "/images/placeholder_teacher.png",
"author": {
"name": "Deepa",
"username": "Deepa",
"location": "",
"avatar": "/images/avatar_teacher.png"
},
@ -709,7 +709,7 @@
"name": "How To",
"icon": "/images/placeholder_howto.png",
"author": {
"name": "Deepa",
"username": "Deepa",
"location": "",
"avatar": "/images/avatar_teacher.png"
},
@ -938,7 +938,7 @@
"name": "Scientist",
"icon": "/images/placeholder_scientist.png",
"author": {
"name": "Paola",
"username": "Paola",
"location": "",
"avatar": "/images/avatar_scientist.png"
},
@ -949,7 +949,7 @@
"name": "Family",
"icon": "/images/placeholder_family.png",
"author": {
"name": "Sita",
"username": "Sita",
"location": "",
"avatar": "/images/avatar_family.png"
},
@ -960,7 +960,7 @@
"name": "Blogger",
"icon": "/images/placeholder_blogger.png",
"author": {
"name": "Emma",
"username": "Emma",
"location": "",
"avatar": "/images/avatar_blogger.png"
},
@ -1051,7 +1051,7 @@
"name": "Club",
"icon": "/images/placeholder_student.png",
"author": {
"name": "Pedro",
"username": "Pedro",
"location": "",
"avatar": "/images/avatar_student.png"
},
@ -1236,7 +1236,7 @@
"name": "Safety",
"icon": "/images/placeholder_safety.png",
"author": {
"name": "Pedro",
"username": "Pedro",
"location": "",
"avatar": "/images/avatar_student.png"
},
@ -1274,10 +1274,10 @@
"name": "Activist",
"icon": "/images/placeholder_activist.png",
"author": {
"name": "Richard",
"username": "Richard",
"location": "",
"avatar": "/images/avatar_activist.png"
},
"blocks": []
}
]
]

Просмотреть файл

@ -259,12 +259,12 @@
"message": "I agree to your terms and conditions",
"description": "Label for terms and conditions checkbox"
},
"Choose a different email": {
"message": "Choose a different email",
"description": "Button for choosing a different email "
"Change": {
"message": "Change",
"description": "Link for changing things, like choosing a different email address for your account"
},
"share_message": {
"message": "Check out the app \"{{app.name}}\" I made with Mozilla Webmaker",
"message": "Check out the app {{app.name}} I made with Mozilla Webmaker",
"description": "Message that gets sent when a published app is shared to friends"
},
"App": {
@ -318,5 +318,33 @@
"Discover": {
"message": "Discover",
"description": "Title for the Discover page (a listing of apps users can choose from)"
},
"Make &amp; share": {
"message": "Make &amp; share",
"description": "Part 1 of 2 for sign-in view headline"
},
"the web": {
"message": "the web",
"description": "Part 2 of 2 for sign-in view headline"
},
"Share": {
"message": "Share",
"description": "Share an app"
},
"Open": {
"message": "Open",
"description": "Open an app"
},
"Create": {
"message": "Create",
"description": "Create an app"
},
"Data": {
"message": "Data",
"description": "Look at the data collected by an app"
},
"Publish": {
"message": "Publish",
"description": "Button label for publishing the current app"
}
}

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "webmaker",
"version": "0.0.2",
"version": "0.0.3",
"repository": {
"type": "git",
"url": "https://github.com/mozillafordevelopment/webmaker-app"
@ -16,7 +16,7 @@
"vue": "0.10.6",
"watchjs": "0.0.0",
"clone": "0.1.18",
"makedrive": "0.0.63",
"makedrive": "k88hudson/makedrive#ffos1.3-patch",
"webmaker-auth-client": "0.2.8",
"xhr": "1.16.1",
"gulp": "3.8.8",

Двоичные данные
static/images/avatar_prompt.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.1 KiB

Двоичные данные
static/images/background.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
static/images/bg_ftu_1.jpg

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 140 KiB

Двоичные данные
static/images/blocks_image.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

После

Ширина:  |  Высота:  |  Размер: 6.2 KiB

Двоичные данные
static/images/blocks_phone.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

После

Ширина:  |  Высота:  |  Размер: 6.1 KiB

Двоичные данные
static/images/blocks_sms.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 6.6 KiB

Двоичные данные
static/images/blocks_text.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 6.5 KiB

Двоичные данные
static/images/ftu_00.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 355 KiB

Двоичные данные
static/images/ftu_01.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 51 KiB

Двоичные данные
static/images/ftu_2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 187 KiB

Двоичные данные
static/images/ftu_3.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 75 KiB

Двоичные данные
static/images/placeholder_activist.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

После

Ширина:  |  Высота:  |  Размер: 8.5 KiB

Двоичные данные
static/images/placeholder_blank.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.1 KiB

После

Ширина:  |  Высота:  |  Размер: 2.4 KiB

Двоичные данные
static/images/placeholder_blogger.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 8.2 KiB

После

Ширина:  |  Высота:  |  Размер: 5.9 KiB

Двоичные данные
static/images/placeholder_family.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

После

Ширина:  |  Высота:  |  Размер: 8.3 KiB

Двоичные данные
static/images/placeholder_howto.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 11 KiB

После

Ширина:  |  Высота:  |  Размер: 3.6 KiB

Двоичные данные
static/images/placeholder_journalist.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 7.5 KiB

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

Двоичные данные
static/images/placeholder_medic.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 6.1 KiB

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
static/images/placeholder_puppy.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 11 KiB

После

Ширина:  |  Высота:  |  Размер: 7.7 KiB

Двоичные данные
static/images/placeholder_safety.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 9.7 KiB

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Двоичные данные
static/images/placeholder_scientist.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 8.4 KiB

Двоичные данные
static/images/placeholder_student.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 11 KiB

После

Ширина:  |  Высота:  |  Размер: 7.3 KiB

Двоичные данные
static/images/placeholder_teacher.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 10 KiB

После

Ширина:  |  Высота:  |  Размер: 7.2 KiB

Двоичные данные
static/images/placeholder_vendor.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 9.7 KiB

После

Ширина:  |  Высота:  |  Размер: 6.9 KiB

Просмотреть файл

@ -11,7 +11,9 @@
</head>
<body>
<div id="app"><div v-view="currentView" class="main"></div></div>
<div id="app">
<div v-view="currentView" class="main"></div>
</div>
<script src="https://login.persona.org/include.js"></script>
<script src="/index.js"></script>
<!-- Analytics -->

Просмотреть файл

@ -46,6 +46,8 @@
padding: 14px 0;
color: @turquoise;
border: none;
border-radius: 0;
background-image: none;
background-color: #FFF;
text-align: center;
text-decoration: none;

Просмотреть файл

@ -26,12 +26,12 @@ body, html {
#app {
height: 100%;
position: relative;
overflow: auto;
}
.main {
height: 100%;
overflow: auto;
.header-space;
.footer-space;
}
.overlay {

Просмотреть файл

@ -13,7 +13,17 @@
// For .main containers
.header-space() {
padding: @header-height 0 @footer-height 0;
padding: @header-height 0 0;
}
.footer-space() {
margin-bottom: @tabBar-height;
}
// For full pages
.full-page() {
padding: 0;
margin: 0;
height: 100%;
}
// Headings for list-cell, forms
@ -36,3 +46,9 @@
padding: 0;
margin: 0;
}
.text-truncate() {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

Просмотреть файл

@ -1,7 +1,7 @@
@fonts-path: '/fonts';
@header-height: 50px;
@footer-height: 70px;
@tabBar-height: 46px;
@editBar-height: 70px;
@body-padding: 14px;
/*********************************************************

Просмотреть файл

@ -1,5 +1,7 @@
var mockrequire = require('mockrequire');
var assert = require('assert');
var templates = require('../../lib/templates.json');
var mockId = '000d1745-5d3c-4997-ac0c-15df68bbbecz';
var mockModelInstance = {
data: { apps: [
@ -8,7 +10,7 @@ var mockModelInstance = {
name: 'Sample App',
icon: '/images/placeholder_puppy.png',
author: {
name: 'Andrew',
username: 'Andrew',
location: 'Portland',
avatar: '/images/avatar_puppy.png'
},
@ -48,12 +50,17 @@ var mockBlocks = function (id) {
var App = mockrequire('../../lib/app', {
'./model': mockModel,
'./blocks': mockBlocks,
'clone': require('clone')
'clone': require('clone'),
'./i18n': {
get: function(key) {
return key;
}
}
});
var app = new App(mockId);
describe('App', function () {
describe('App instance', function () {
describe('interface', function () {
it('should have expected properties', function () {
assert.equal(app.id, mockId);
@ -93,4 +100,24 @@ describe('App', function () {
});
describe('App', function () {
describe('#createApp', function () {
it('should be a function', function () {
assert.equal(typeof App, 'function');
});
it('should return undefined when no template or data is passed in', function () {
assert.equal(typeof App.createApp(), 'undefined');
assert.equal(typeof App.createApp({template: 'notrealid'}), 'undefined');
});
it('should return an app instance for valid template id', function () {
var template = templates[2];
var app = App.createApp({template: template.id, name: 'Bob is my cat'});
assert.ok(app instanceof App);
assert.ok(app.id && app.id !== template.id);
assert.equal(app.data.name, 'Bob is my cat');
});
});
});

Просмотреть файл

@ -74,7 +74,7 @@ var authorSchema = {
pattern: '(^/images/.*)|'
}
},
required: ['name', 'location', 'avatar']
required: ['username', 'location', 'avatar']
};
// Template schemas

Просмотреть файл

@ -1,5 +1,6 @@
#add {
padding: 0;
.full-page;
position: absolute;
top: 0;
left: 0;

Просмотреть файл

@ -5,22 +5,28 @@
<img class="app-icon" src="{{app.icon}}" alt="{{app.name}}">
<hgroup>
<h3>{{app.name}}</h3>
<p class="text-light">by Kate</p>
<p class="text-light" v-bind-html="'by _'" v-with="name: app.author.username"></p>
</hgroup>
</header>
<ul id="detail-share">
<li><a href="/make/{{id}}/share">
<span class="fa fa-2x fa-fw fa-share-alt"></span><br>Share</a>
<li v-if="!isTemplate"><a href="/make/{{id}}/share">
<span class="fa fa-2x fa-fw fa-share-alt"></span><br>{{ 'Share' | i18n }}</a>
</li>
<li><a href="/make/{{id}}/play">
<span class="fa fa-2x fa-fw fa-eye"></span><br>Open</a>
<li v-if="!isTemplate"><a href="/make/{{id}}/play">
<span class="fa fa-2x fa-fw fa-eye"></span><br>{{ 'Open' | i18n }}</a>
</li>
<li v-if="isTemplate"><a href="" class="disabled">
<span class="fa fa-2x fa-fw fa-eye"></span><br>{{ 'Preview' | i18n }}</a>
</li>
<li v-if="isTemplate"><a href="#" v-on="click: create">
<span class="fa fa-2x fa-fw fa-edit"></span><br>{{ 'Create' | i18n }}</a>
</li>
<li><a href="" class="disabled">
<span class="fa fa-2x fa-fw fa-list"></span><br>Data</a>
<span class="fa fa-2x fa-fw fa-list"></span><br>{{ 'Data' | i18n }}</a>
</li>
</ul>
<p v-if="app.url" class="text-center">
<a href="{{app.url}}">View published app</a>
<a target="_blank" href="{{app.url}}">View published app</a>
</p>
</div>
<div v-component="tabBar"></div>

Просмотреть файл

@ -1,5 +1,7 @@
var App = require('../../lib/app');
var view = require('../../lib/view');
var templates = require('../../lib/templates.json');
var utils = require('../../lib/utils');
module.exports = view.extend({
id: 'detail',
@ -8,14 +10,27 @@ module.exports = view.extend({
back: true,
title: 'App'
},
methods: {
create: function () {
var self = this;
var app = App.createApp({
data: self.$data.app
});
self.page('/make/' + app.id + '/edit');
}
},
created: function () {
var self = this;
// Fetch app
var id = self.$parent.$data.params.id;
var app = new App(id);
var app = new App(id).data;
if (!app) {
app = templates[utils.findInArray(templates, 'id', id)] || {};
self.$data.isTemplate = true;
}
// Bind app
self.$data.id = id;
self.$data.app = app.data || {};
self.$data.app = app;
}
});

Просмотреть файл

@ -14,7 +14,7 @@ TODO: Restore this toggle when we have implemented 'nearby' view.
<ul class="list-cell" v-show="mode === 'featured'">
<lh>{{ "Featured Apps" | i18n }}</lh>
<li v-component="appCell" v-repeat="apps.featured"></li>
<li v-component="appCell" v-repeat="apps.featured" mode="detail"></li>
</ul>
<ul class="list-cell" v-show="mode === 'nearby'">

Просмотреть файл

@ -1,5 +1,5 @@
var view = require('../../lib/view');
var fakeDiscovery = require('../../lib/fake-discovery.json');
var fakeDiscovery = require('../../lib/fake-discovery');
module.exports = view.extend({
id: 'discover',

Просмотреть файл

@ -1,5 +1,6 @@
<div v-if="!app.id" v-component="alert" type="error" message="errorAppNotFound"></div>
<div v-if="app.id">
<div v-component="navigationBar" v-with="title: 'Edit'"></div>
<input id="name-input" type="text" v-model="app.name">
<a class="add" href="/make/{{app.id}}/add">+</a>
<div id="blocks">

Просмотреть файл

@ -7,7 +7,8 @@ module.exports = view.extend({
id: 'edit',
template: require('./index.html'),
data: {
cancel: '/profile'
back: '/profile',
doneLabel: 'Publish'
},
created: function () {
var self = this;

Просмотреть файл

@ -1,4 +1,5 @@
#edit {
margin-bottom: @editBar-height;
a.add {
display: flex;
justify-content: center;
@ -6,7 +7,7 @@
width: 95%;
height: 44px;
margin: 21px 2.5% 15px 2.5%;
margin: 15px 2.5% 15px 2.5%;
border: 1px dashed @highlight;
background-color: transparent;
@ -34,19 +35,18 @@
}
#name-input {
position: fixed;
left: 0;
top: 0;
z-index: 1;
width: 95%;
height: 50px;
color: @highlight;
cursor: pointer;
text-align: center;
font-size: 1.1em;
font-weight: 400;
margin: 0;
margin: 15px 2.5% 0;
border: 1px dashed @turquoise;
&:focus {
border: 1px dashed @turquoise;
outline: none;
}
}

Просмотреть файл

@ -12,7 +12,7 @@ module.exports = view.extend({
message = 'error404';
break;
default:
message = 'defaultError'
message = 'defaultError';
}
return message;
}

Просмотреть файл

@ -1,5 +1,7 @@
#error {
.full-page;
padding-top: 0;
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: center;

Просмотреть файл

@ -1,4 +1,5 @@
#loader {
.full-page;
display: flex;
width: 100%;
align-items: center;

Просмотреть файл

@ -1,5 +1,4 @@
var App = require('../../lib/app');
var templates = require('../../lib/templates.json');
var view = require('../../lib/view');
var Data = require('../../lib/data');
@ -7,7 +6,8 @@ module.exports = view.extend({
id: 'play',
template: require('./index.html'),
data: {
cancel: '/profile'
back: '/profile',
doneLabel: 'Publish'
},
created: function () {
var self = this;
@ -19,7 +19,7 @@ module.exports = view.extend({
// Bind app
self.$data.app = app.data || {};
self.$data.onDone = '/make/' + id + '/share';
self.$data.onDone = '/make/' + id + '/share?publish=true';
// Listen for Data Submitted by the User
var data = new Data(id);

3
views/play/index.less Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#play {
margin-bottom: @editBar-height;
}

Просмотреть файл

@ -1,18 +1,15 @@
<div v-component="navigationBar"></div>
<form v-show="!isPublishing">
<h3 v-show="app.url" class="section">URL</h3>
<div v-show="app.url" class="form-group">
<a href="{{app.url}}">{{app.url}}</a>
<div v-show="error" v-component="alert" type="error" message="{{error}}"></div>
<div v-show="!error">
<h3 class="section">Share via SMS</h3>
<div v-show="user.username" class="form-group">
<textarea name="share-message" v-model="shareMessage" class="textarea-large"></textarea>
</div>
</div>
<h3 class="section">Share by SMS</h3>
<div class="form-group" v-show="!user.username">
<button v-on="click: login" class="btn btn-block">Log in or sign up</button>
</div>
<div v-show="user.username" class="form-group">
<textarea name="share-message" v-model="shareMessage" class="textarea-large"></textarea>
</div>
</form>
<div v-show="isPublishing" id="loader">

Просмотреть файл

@ -5,20 +5,32 @@ var publish = require('../../lib/publish');
var auth = require('../../lib/auth');
var page = require('page');
var PUBLISH_TIMEOUT = 20000;
module.exports = view.extend({
id: 'share',
template: require('./index.html'),
data: {
title: 'Share',
cancel: true,
error: false,
isPublishing: true,
doneDisabled: true
},
methods: {
login: function (e) {
e.preventDefault();
auth.login();
},
onDone: function () {
var self = this;
if (!self.$data.app.url) return;
var sms = 'sms:?body=' + encodeURIComponent(self.$data.shareMessage);
window.location = sms;
page('/make/' + self.$parent.$data.params.id + '/detail');
}
},
created: function () {
ready: function () {
var self = this;
// Fetch app
@ -33,33 +45,47 @@ module.exports = view.extend({
// Share message
var message = i18n.get('share_message').replace('{{app.name}}', app.data.name);
self.$data.shareMessage = message;
self.$data.shareMessage = message + ': ' + app.data.url;
if (!global.location.search.match('publish=true') && app.data.url) {
self.$data.isPublishing = false;
return;
}
// Publish
console.log('Starting publish...');
self.$data.doneDisabled = true;
var sync = self.model._sync;
self.$data.onDone = function () {
if (self.$data.isPublishing) return;
var isSynced = false;
var syncTimeout;
function onSynced() {
publish(id, self.$data.user.username, function (err, data) {
self.$data.isPublishing = false;
if (err) return console.error(err);
app.data.url = data.url;
var sms = 'sms:?body=' + encodeURI(self.$data.shareMessage) + ' ' + data.url;
window.location = sms;
page('/make/' + id + '/detail');
});
}
function onSynced() {
publish(id, self.$data.user.username, function (err, data) {
global.clearTimeout(syncTimeout);
self.$data.isPublishing = false;
if (err) {
console.error(err);
self.$data.error = (err.status || 'Error') + ': ' + err.message;
return;
}
console.log('Published!');
self.$data.error = false;
self.$data.doneDisabled = false;
app.data.url = data.url;
self.$data.shareMessage = message + ': ' + data.url;
});
}
// Show spinner
self.$data.isPublishing = true;
syncTimeout = global.setTimeout(function() {
console.log('timed out');
self.$data.isPublishing = false;
self.$data.error = 'Oops! Your publish is taking too long';
}, PUBLISH_TIMEOUT);
// Sync makedrive - todo. Request doesn't seem to work
// sync.once('completed', onSynced);
// sync.request();
onSynced();
onSynced();
};
// sync.once('completed', onSynced);
}
});

Просмотреть файл

@ -1,3 +1,7 @@
<div class="top">
<h1>{{ 'Make &amp; share' | i18n }}</br>{{ 'the web' | i18n }}</h1>
</div>
<div class="bottom">
<div v-if="!offline" >
<a v-if="username" href="/profile" class="btn-next">{{ 'Get Started' | i18n }}</a>

Просмотреть файл

@ -1,9 +1,31 @@
#sign-in {
.full-page;
.header-space;
background: @turquoise;
background-image: url(/images/background.gif);
background-size: 400px;
background-position: 0px -20px;
color: @white;
text-align: center;
.top {
width: 100%;
margin: 5% auto 0 auto;
padding: @body-padding;
.animated;
.fadeIn;
h1 {
font-weight: 400;
font-size: 2.6em;
line-height: 1em;
}
}
.bottom {
padding: @body-padding;
background: @turquoise;
position: fixed;
bottom: 0;
left: 0;

Просмотреть файл

@ -1,22 +1,19 @@
<div v-component="navigationBar"></div>
<div class="form-group">
<label for="email">{{ 'Email' | i18n }}</label>
<input type="text" id="email" v-model="email">
<p>
<button class="btn" v-on="click: login">{{ 'Choose a different email' | i18n }}</button>
</p>
<div class="email">
<h3>{{ 'Email' | i18n }}</h3>
{{ email || 'your@email.com' }} - <a v-on="click: login">{{ 'Change' | i18n }}</a>
</div>
<form>
<div class="form-group">
<label for="username">{{ 'Choose a username' | i18n }}</label>
<input type="text" id="username" v-model="user.username" v-on="keyup: checkUsernameExists">
<div class="error" id="usernameTaken" v-if="show: errors.usernameTaken">
<div class="form-error" id="usernameTaken" v-if="show: errors.usernameTaken">
{{'Sorry, that name has already been snagged! Please try another.' | i18n}}
</div>
</div>
<div class="checkbox">
<label for="mailing-list">
<input type="checkbox" id="mailing-list" v-model="user.mailingList">

Просмотреть файл

@ -16,15 +16,19 @@ module.exports = view.extend({
usernameTaken: false
}
},
computed: {
doneDisabled: function () {
var self = this;
return !self.$data.user.username ||
!self.$data.user.terms ||
!auth._assertion ||
self.$data.errors.usernameTaken;
}
},
methods: {
onDone: function () {
var self = this;
if (!self.$data.user.username) {
return;
}
if (!self.$data.user.terms) {
return;
}
if (self.$data.doneDisabled) return;
auth.createUser({
assertion: auth._assertion,
@ -59,5 +63,10 @@ module.exports = view.extend({
auth.on('newuser', function (assertion, email) {
self.$data.email = email;
});
setTimeout(function() {
auth.logout();
self.model.offlineConnect();
self.page('/sign-in');
}, 60000);
}
});

17
views/sign-up/index.less Normal file
Просмотреть файл

@ -0,0 +1,17 @@
#sign-up {
.email {
font-size: 14px;
padding: 14px;
color: #638093;
h3 {
font-size: inherit;
margin: 0 0 5px 0;
padding: 0;
}
a {
cursor: pointer;
}
}
}

Просмотреть файл

@ -2,5 +2,4 @@
<ul>
<li v-component="templateCell" v-repeat="templates"></li>
</ul>
<div class="tab-bar-space">&nbsp;</div>
<div v-component="tabBar"></div>

Просмотреть файл

@ -1,7 +1,6 @@
var templates = require('../../lib/templates.json');
var uuid = require('../../lib/uuid');
var view = require('../../lib/view');
var i18n = require('../../lib/i18n');
var App = require('../../lib/app');
module.exports = view.extend({
id: 'templates',
@ -13,30 +12,13 @@ module.exports = view.extend({
ready: function () {
var self = this;
// Template clone helper
function getTemplateClone (id) {
for (var i = 0; i < templates.length; i++) {
if (templates[i].id === id) {
return JSON.parse(JSON.stringify(templates[i]));
}
}
}
// Click handler
function clickHandler (e) {
e.preventDefault();
var id = e.currentTarget.getAttribute('data-id');
var clone = getTemplateClone(id);
// Prepare the clone for use
clone.id = uuid();
clone.name = i18n.get('Untitled App');
clone.author = self.model.data.user;
// Add to model & redirect to editor
self.model.data.apps.unshift(clone);
self.page('/make/' + clone.id + '/play');
var app = App.createApp({template: id});
self.page('/make/' + app.id + '/edit');
}
// Apply click handler to each cell

Просмотреть файл

@ -1,14 +1,5 @@
#templates {
padding: 50px 0 @tabBar-height 0;
}
#templates ul {
margin: 0 0 0 0; //Bottom margin as much as bottom tabbar.
padding: 0;
.clearfix;
}
.tab-bar-space {
width: 100%;
height: @header-height;
}