Commit b85aa245 authored by Wolfgang Knopki's avatar Wolfgang Knopki
Browse files

Merge branch 'mnt' into 'master'

Mnt

See merge request !2
parents 2fc14e1e fff0340f
...@@ -138,7 +138,6 @@ router.get('/', function(req, res, next) { ...@@ -138,7 +138,6 @@ router.get('/', function(req, res, next) {
"$exists": 1 "$exists": 1
} }
}).populate("space").exec(function(err, memberships) { }).populate("space").exec(function(err, memberships) {
async.map(memberships, function(membership, memcb) { async.map(memberships, function(membership, memcb) {
Space.getRecursiveSubspacesForSpace(membership.space, function(err, spaces) { Space.getRecursiveSubspacesForSpace(membership.space, function(err, spaces) {
cb(null, spaces.map(function(s) { cb(null, spaces.map(function(s) {
......
...@@ -51,8 +51,7 @@ router.get('/png', function(req, res, next) { ...@@ -51,8 +51,7 @@ router.get('/png', function(req, res, next) {
if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) { if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) {
db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }}); db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }});
phantom.takeScreenshot(req.space, "png", phantom.takeScreenshot(req.space, "png", function(local_path) {
function(local_path) {
var localResizedFilePath = local_path + ".thumb.jpg"; var localResizedFilePath = local_path + ".thumb.jpg";
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) { gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
...@@ -79,14 +78,14 @@ router.get('/png', function(req, res, next) { ...@@ -79,14 +78,14 @@ router.get('/png', function(req, res, next) {
var oldPath = url.parse(oldUrl).pathname; var oldPath = url.parse(oldUrl).pathname;
uploader.removeFile(oldPath, function(err, res) {}); uploader.removeFile(oldPath, function(err, res) {});
} }
fs.unlink(local_path); fs.unlinkSync(local_path);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}); });
try { try {
fs.unlink(localResizedFilePath); fs.unlinkSync(localResizedFilePath);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
...@@ -95,7 +94,7 @@ router.get('/png', function(req, res, next) { ...@@ -95,7 +94,7 @@ router.get('/png', function(req, res, next) {
}, },
function() { function() {
// on_error // on_error
console.error("phantom could not create screenshot for space " + req.space_id); console.error("[space screenshot] could not create screenshot for space " + req.space_id);
res.status(404).send("Not found"); res.status(404).send("Not found");
}); });
} else { } else {
......
...@@ -45,10 +45,12 @@ router.post('/', function(req, res, next) { ...@@ -45,10 +45,12 @@ router.post('/', function(req, res, next) {
"email": membership.email_invited "email": membership.email_invited
}}).then(function(user) { }}).then(function(user) {
// existing user? then immediately activate membership
if (user) { if (user) {
membership.user_id = user._id; membership.user_id = user._id;
membership.state = "active"; membership.state = "active";
} else { } else {
// if not, invite via email and invite code
membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12); membership.code = crypto.randomBytes(64).toString('hex').substring(0, 12);
} }
...@@ -84,13 +86,13 @@ router.post('/', function(req, res, next) { ...@@ -84,13 +86,13 @@ router.post('/', function(req, res, next) {
} else { } else {
res.status(400).json({ res.status(400).json({
"error": "user already in space" "error": "This email is already included in the Space memberships."
}); });
} }
} else { } else {
res.status(403).json({ res.status(403).json({
"error": "not_permitted" "error": "Only administrators can do that."
}); });
} }
}); });
...@@ -102,11 +104,18 @@ router.put('/:membership_id', function(req, res, next) { ...@@ -102,11 +104,18 @@ router.put('/:membership_id', function(req, res, next) {
_id: req.params.membership_id _id: req.params.membership_id
}}).then(function(mem) { }}).then(function(mem) {
if (mem) { if (mem) {
var attrs = req.body; // is the user trying to change their own role?
mem.role = attrs.role; if (mem.user_id == req.user._id) {
mem.save(function() { res.status(400).json({
res.status(201).json(mem); "error": "Cannot change your own role."
}); });
} else {
var attrs = req.body;
mem.role = attrs.role;
mem.save(function() {
res.status(201).json(mem);
});
}
} }
}); });
} else { } else {
...@@ -118,13 +127,25 @@ router.put('/:membership_id', function(req, res, next) { ...@@ -118,13 +127,25 @@ router.put('/:membership_id', function(req, res, next) {
}); });
router.delete('/:membership_id', function(req, res, next) { router.delete('/:membership_id', function(req, res, next) {
if (req.user) { if (req.user && req.spaceRole == 'admin') {
db.Membership.findOne({ where: { db.Membership.count({ where: {
_id: req.params.membership_id space_id: req.space._id,
}}).then(function(mem) { role: "admin"
mem.destroy().then(function() { }}).then(function(adminCount) {
res.sendStatus(204); db.Membership.findOne({ where: {
}); _id: req.params.membership_id
}}).then(function(mem) {
// deleting an admin? need at least 1
if (mem.role != "admin" || adminCount > 1) {
mem.destroy().then(function() {
res.sendStatus(204);
});
} else {
res.status(400).json({
"error": "Space needs at least one administrator."
});
}
})
}); });
} else { } else {
res.sendStatus(403); res.sendStatus(403);
......
...@@ -42,80 +42,63 @@ var spaceMapping = { ...@@ -42,80 +42,63 @@ var spaceMapping = {
thumbnail_url: 1 thumbnail_url: 1
}; };
function listSpacesInFolder(req, res, parent_space_id) {
db.Space
.findOne({where: {
_id: parent_space_id
}})
.then(function(space) {
if (space) {
function spacesForRole(role) {
if (role == "none") {
if (space.access_mode == "public") {
role = "viewer";
}
}
if (role != "none") {
db.Space
.findAll({where:{
parent_space_id: parent_space_id
}, include:[db.CreatorSafeInclude(db)]})
.then(function(spaces) {
res.status(200).json(spaces);
});
} else {
res.status(403).json({"error": "not authorized"});
}
}
if (req["spaceAuth"] && space.edit_hash) {
// TODO could be editor, too
spacesForRole("none");
} else {
db.getUserRoleInSpace(space, req.user, spacesForRole);
}
} else {
res.status(404).json({"error": "space not found"});
}
});
}
router.get('/', function(req, res, next) { router.get('/', function(req, res, next) {
if (req.query.parent_space_id && req["spaceAuth"]) {
// list subspaces of a space authorized anonymously
listSpacesInFolder(req, res, req.query.parent_space_id);
return;
}
if (!req.user) { if (!req.user) {
res.status(403).json({ res.status(403).json({
error: "auth required" error: "auth required"
}); });
} else { } else {
if (req.query.writablefolders) { if (req.query.search) {
db.Membership.find({where: {
user_id: req.user._id
}}, (memberships) => {
var validMemberships = memberships.filter((m) => {
if (!m.space_id || (m.space_id == "undefined"))
return false;
return true;
});
var editorMemberships = validMemberships.filter((m) => {
return (m.role == "editor") || (m.role == "admin")
});
var spaceIds = editorMemberships.map(function(m) {
return m.space_id;
});
// TODO port
var q = {
"space_type": "folder",
"$or": [{
"creator": req.user._id
}, {
"_id": {
"$in": spaceIds
},
"creator": {
"$ne": req.user._id
}
}]
};
db.Space
.findAll({where: q})
.then(function(spaces) {
var updatedSpaces = spaces.map(function(s) {
var spaceObj = s; //.toObject();
return spaceObj;
});
async.map(spaces, (space, cb) => {
Space.getRecursiveSubspacesForSpace(space, (err, spaces) => {
var allSpaces = spaces;
cb(err, allSpaces);
})
}, (err, spaces) => {
var allSpaces = _.flatten(spaces);
var onlyFolders = _.filter(allSpaces, (s) => {
return s.space_type == "folder";
})
var uniqueFolders = _.unique(onlyFolders, (s) => {
return s._id;
})
res.status(200).json(uniqueFolders);
});
});
});
} else if (req.query.search) {
db.Membership.findAll({where:{ db.Membership.findAll({where:{
user_id: req.user._id user_id: req.user._id
}}).then(memberships => { }}).then(memberships => {
// search for spaces
var validMemberships = memberships.filter(function(m) { var validMemberships = memberships.filter(function(m) {
if (!m.space_id || (m.space_id == "undefined")) if (!m.space_id || (m.space_id == "undefined"))
return false; return false;
...@@ -133,7 +116,7 @@ router.get('/', function(req, res, next) { ...@@ -133,7 +116,7 @@ router.get('/', function(req, res, next) {
{"_id": {[Op.in]: spaceIds}}, {"_id": {[Op.in]: spaceIds}},
{"parent_space_id": {[Op.in]: spaceIds}}], {"parent_space_id": {[Op.in]: spaceIds}}],
name: {[Op.like]: "%"+req.query.search+"%"} name: {[Op.like]: "%"+req.query.search+"%"}
}, include: ['creator']}; }, include: [db.CreatorSafeInclude(db)]};
db.Space db.Space
.findAll(q) .findAll(q)
...@@ -143,47 +126,21 @@ router.get('/', function(req, res, next) { ...@@ -143,47 +126,21 @@ router.get('/', function(req, res, next) {
}); });
} else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) { } else if (req.query.parent_space_id && req.query.parent_space_id != req.user.home_folder_id) {
// list spaces in a folder
db.Space
.findOne({where: { listSpacesInFolder(req, res, req.query.parent_space_id);
_id: req.query.parent_space_id
}})
//.populate('creator', userMapping)
.then(function(space) {
if (space) {
db.getUserRoleInSpace(space, req.user, function(role) {
if (role == "none") {
if (space.access_mode == "public") {
role = "viewer";
}
}
if (role != "none") {
db.Space
.findAll({where:{
parent_space_id: req.query.parent_space_id
}, include:['creator']})
.then(function(spaces) {
res.status(200).json(spaces);
});
} else {
res.status(403).json({"error": "no authorized"});
}
});
} else {
res.status(404).json({"error": "space not found"});
}
});
} else { } else {
// list home folder and spaces/folders that the user is a member of
db.Membership.findAll({ where: { db.Membership.findAll({ where: {
user_id: req.user._id user_id: req.user._id
}}).then(memberships => { }}).then(memberships => {
if (!memberships) memberships = []; if (!memberships) memberships = [];
var validMemberships = memberships.filter(function(m) { var validMemberships = memberships.filter(function(m) {
if (!m.space_id || (m.space_id == "undefined")) if (!m.space_id || (m.space_id == "undefined"))
return false; return false;
return true;
}); });
var spaceIds = validMemberships.map(function(m) { var spaceIds = validMemberships.map(function(m) {
...@@ -205,7 +162,7 @@ router.get('/', function(req, res, next) { ...@@ -205,7 +162,7 @@ router.get('/', function(req, res, next) {
}; };
db.Space db.Space
.findAll({where: q, include: ['creator']}) .findAll({where: q, include: [db.CreatorSafeInclude(db)]})
.then(function(spaces) { .then(function(spaces) {
var updatedSpaces = spaces.map(function(s) { var updatedSpaces = spaces.map(function(s) {
var spaceObj = db.spaceToObject(s); var spaceObj = db.spaceToObject(s);
...@@ -227,15 +184,19 @@ router.post('/', function(req, res, next) { ...@@ -227,15 +184,19 @@ router.post('/', function(req, res, next) {
attrs._id = uuidv4(); attrs._id = uuidv4();
attrs.creator_id = req.user._id; attrs.creator_id = req.user._id;
attrs.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7); attrs.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7);
attrs.edit_slug = slug(attrs.name); attrs.edit_slug = attrs.edit_slug || slug(attrs.name);
attrs.access_mode = "private";
db.Space.create(attrs).then(createdSpace => { db.Space.create(attrs).then(createdSpace => {
//if (err) res.sendStatus(400); res.status(201).json(createdSpace);
// create initial admin membership
var membership = { var membership = {
_id: uuidv4(), _id: uuidv4(),
user_id: req.user._id, user_id: req.user._id,
space_id: attrs._id, space_id: attrs._id,
role: "admin" role: "admin",
state: "active"
}; };
db.Membership.create(membership).then(() => { db.Membership.create(membership).then(() => {
...@@ -265,6 +226,7 @@ router.post('/', function(req, res, next) { ...@@ -265,6 +226,7 @@ router.post('/', function(req, res, next) {
} }
}); });
} else { } else {
attrs.parent_space_id = req.user.home_folder_id;
createSpace(); createSpace();
} }
...@@ -314,8 +276,17 @@ router.put('/:id', function(req, res) { ...@@ -314,8 +276,17 @@ router.put('/:id', function(req, res) {
newAttr.edit_slug = slug(newAttr['name']); newAttr.edit_slug = slug(newAttr['name']);
delete newAttr['_id']; delete newAttr['_id'];
delete newAttr['editor_name'];
delete newAttr['creator']; delete newAttr['creator'];
delete newAttr['creator_id'];
delete newAttr['space_type'];
if (req['spaceRole'] != "admin") {
delete newAttr['access_mode']
delete newAttr['password']
delete newAttr['edit_hash']
delete newAttr['edit_slug']
delete newAttr['editors_locking']
}
db.Space.update(newAttr, {where: { db.Space.update(newAttr, {where: {
"_id": space._id "_id": space._id
...@@ -362,43 +333,6 @@ router.post('/:id/background', function(req, res, next) { ...@@ -362,43 +333,6 @@ router.post('/:id/background', function(req, res, next) {
}); });
}); });
var handleDuplicateSpaceRequest = function(req, res, parentSpace) {
Space.duplicateSpace(req.space, req.user, 0, (err, newSpace) => {
if (err) {
console.error(err);
res.status(400).json(err);
} else {
res.status(201).json(newSpace);
}
}, parentSpace);
}
router.post('/:id/duplicate', (req, res, next) => {
if (req.query.parent_space_id) {
Space.findOne({
_id: req.query.parent_space_id
}).populate('creator', userMapping).exec((err, parentSpace) => {
if (!parentSpace) {
res.status(404).json({
"error": "parent space not found for duplicate"
});
} else {
db.getUserRoleInSpace(parentSpace, req.user, (role) => {
if (role == "admin" ||  role == "editor") {
handleDuplicateSpaceRequest(req, res, parentSpace);
} else {
res.status(403).json({
"error": "not authed for parent_space_id"
});
}
});
}
});
} else {
handleDuplicateSpaceRequest(req, res);
}
});
router.delete('/:id', function(req, res, next) { router.delete('/:id', function(req, res, next) {
if (req.user) { if (req.user) {
const space = req.space; const space = req.space;
...@@ -418,136 +352,4 @@ router.delete('/:id', function(req, res, next) { ...@@ -418,136 +352,4 @@ router.delete('/:id', function(req, res, next) {
} }
}); });
router.post('/:id/artifacts-pdf', function(req, res, next) {
if (req.spaceRole == "editor" || req.spaceRole == "admin") {
var withZones = (req.query.zones) ? req.query.zones == "true" : false;
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9\.]/g, '');
var localFilePath = os.tmpdir() + "/" + fileName;
var writeStream = fs.createWriteStream(localFilePath);
var stream = req.pipe(writeStream);
req.on('end', function() {
var rawName = fileName.slice(0, fileName.length - 4);
var outputFolder = os.tmpdir() + "/" + rawName;
fs.mkdir(outputFolder, function(err) {
var images = outputFolder + "/" + rawName + "-page-%03d.jpeg";
// FIXME not portable
exec.execFile("gs", ["-sDEVICE=jpeg", "-dDownScaleFactor=4", "-dDOINTERPOLATE", "-dNOPAUSE", "-dJPEGQ=80", "-dBATCH", "-sOutputFile=" + images, "-r250", "-f", localFilePath], {}, function(error, stdout, stderr) {
if (error === null) {
glob(outputFolder + "/*.jpeg", function(er, files) {
var count = files.length;
var delta = 10;
var limitPerRow = Math.ceil(Math.sqrt(count));
var startX = parseInt(req.query.x, delta);
var startY = parseInt(req.query.y, delta);
async.mapLimit(files, 20, function(localfilePath, cb) {
var fileName = path.basename(localfilePath);
var baseName = path.basename(localfilePath, ".jpeg");
var number = parseInt(baseName.slice(baseName.length - 3, baseName.length), 10);
gm(localFilePath).size((err, size) => {
var w = 350;
var h = w;
var x = startX + (((number - 1) % limitPerRow) * w);
var y = startY + ((parseInt(((number - 1) / limitPerRow), 10) + 1) * w);
var userId;
if (req.user) userId = req.user._id;
var a = db.Artifact.create({
_id: uuidv4(),
mime: "image/jpg",
space_id: req.space._id,
user_id: userId,
editor_name: req.guest_name,
w: w,
h: h,
x: x,
y: y,
z: (number + (count + 100))
}).then(a => {
payloadConverter.convert(a, fileName, localfilePath, (error, artifact) => {
if (error) res.status(400).json(error);
else {
if (withZones) {
var zone = {
_id: uuidv4(),
mime: "x-spacedeck/zone",
description: "Zone " + (number),
space_id: req.space._id,
user_id: userId,
editor_name: req.guest_name,
w: artifact.w + 20,
h: artifact.h + 40,
x: x - 10,
y: y - 30,
z: number,
order: number,
valign: "middle",
align: "center"
};
db.Artifact.create(zone).then((z) => {
redis.sendMessage("create", "Artifact", z.toJSON(), req.channelId);
cb(null, [artifact, zone]);
});
} else {
cb(null, [artifact]);
}
}
});
});
});
}, function(err, artifacts) {
// FIXME not portable
exec.execFile("rm", ["-r", outputFolder], function(err) {
res.status(201).json(_.flatten(artifacts));
async.eachLimit(artifacts, 10, (artifact_or_artifacts, cb) => {
if (artifact_or_artifacts instanceof Array) {
_.each(artifact_or_artifacts, (a) => {
redis.sendMessage("create", "Artifact", JSON.stringify(a), req.channelId);
});
} else  {
redis.sendMessage("create", "Artifact", JSON.stringify(artifact_or_artifacts), req.channelId);
}
cb(null);
});
});
});
});
} else {
console.error("error:", error);
// FIXME not portable
exec.execFile("rm", ["-r", outputFolder], function(err) {
fs.unlink(localFilePath);
res.status(400).json({});
});
}
});
});
});
} else {
res.status(401).json({
"error": "no access"
});
}
});
module.exports = router; module.exports = router;
...@@ -11,7 +11,6 @@ var importer = require('../../helpers/importer'); ...@@ -11,7 +11,6 @@ var importer = require('../../helpers/importer');
var bcrypt = require('bcryptjs'); var bcrypt = require('bcryptjs');
var crypto = require('crypto'); var crypto = require('crypto');
var swig = require('swig');
var async = require('async'); var async = require('async');
var _ = require('underscore'); var _ = require('underscore');
var fs = require('fs'); var fs = require('fs');
...@@ -51,12 +50,18 @@ router.post('/', function(req, res) { ...@@ -51,12 +50,18 @@ router.post('/', function(req, res) {
var nickname = req.body["nickname"]; var nickname = req.body["nickname"];
var password = req.body["password"]; var password = req.body["password"];
var password_confirmation = req.body["password_confirmation"]; var password_confirmation = req.body["password_confirmation"];
var invite_code = req.body["invite_code"];
if (password_confirmation != password) { if (password_confirmation != password) {
res.status(400).json({"error":"password_confirmation"}); res.status(400).json({"error":"password_confirmation"});
return; return;
} }
if (config.invite_code && invite_code != config.invite_code) {
res.status(400).json({"error":"Invalid Invite Code."});
return;
}
if (!validator.isEmail(email)) { if (!validator.isEmail(email)) {
res.status(400).json({"error":"email_invalid"}); res.status(400).json({"error":"email_invalid"});
return; return;
...@@ -83,28 +88,31 @@ router.post('/', function(req, res) { ...@@ -83,28 +88,31 @@ router.post('/', function(req, res) {
res.sendStatus(400); res.sendStatus(400);
}) })
.then(u => { .then(u => {
var homeSpace = { var homeFolder = {
_id: uuidv4(), _id: uuidv4(),
name: req.i18n.__("home"), name: req.i18n.__("home"),
space_type: "folder", space_type: "folder",
creator_id: u._id creator_id: u._id
}; };
db.Space.create(homeSpace) db.Space.create(homeFolder)
.error(err => { .error(err => {
res.sendStatus(400); res.sendStatus(400);
}) })
.then(homeSpace => { .then(homeFolder => {
u.home_folder_id = homeSpace._id; u.home_folder_id = homeFolder._id;
u.save() u.save()
.then(() => { .then(() => {
res.status(201).json({}); // home folder created,
// auto accept pending invites
mailer.sendMail(u.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), { db.Membership.update({
action: { "state": "active"
link: config.endpoint + "/confirm/" + u.confirmation_token, }, {
name: req.i18n.__("confirm_action") where: {
"email_invited": u.email,
"state": "pending"
} }
}); });
res.status(201).json({});
}) })
.error(err => { .error(err => {
res.status(400).json(err); res.status(400).json(err);
...@@ -119,7 +127,6 @@ router.post('/', function(req, res) { ...@@ -119,7 +127,6 @@ router.post('/', function(req, res) {
db.User.findAll({where: {email: email}}) db.User.findAll({where: {email: email}})
.then(users => { .then(users => {
if (users.length == 0) { if (users.length == 0) {
//var domain = email.slice(email.lastIndexOf('@')+1);
createUser(); createUser();
} else { } else {
res.status(400).json({"error":"user_email_already_used"}); res.status(400).json({"error":"user_email_already_used"});
...@@ -168,36 +175,35 @@ router.post('/:id/password', function(req, res, next) { ...@@ -168,36 +175,35 @@ router.post('/:id/password', function(req, res, next) {
}); });
}); });
} else { } else {
res.status(403).json({"error": "old password wrong"}); res.status(403).json({"error": "Please enter the correct current password."});
} }
} else { } else {
res.status(403).json({"error": "wrong user"}); res.status(403).json({"error": "Access denied."});
} }
} else { } else {
res.status(400).json({"error": "password_to_short"}); res.status(400).json({"error": "Please choose a new password with at least 6 characters."});
} }
}); });
router.delete('/:id', (req, res, next) => { router.delete('/:id', (req, res, next) => {
const user = req.user; const user = req.user;
if(user._id == req.params.id) { if (user._id == req.params.id) {
if (user.account_type == 'email') { if (bcrypt.compareSync(req.query.password, user.password_hash)) {
if (bcrypt.compareSync(req.query.password, user.password_hash)) {
user.remove((err) => { // TODO: this doesn't currently work.
if(err)res.status(400).json(err); // all objects (indirectly) belonging to the user have
else res.sendStatus(204); // to be walked and deleted first.
});
} else { user.destroy().then(err => {
res.bad_request("password_incorrect"); if(err)res.status(400).json(err);
}
} else {
user.remove((err) => {
if (err) res.status(400).json(err);
else res.sendStatus(204); else res.sendStatus(204);
}); });
} else {
res.bad_request("Please enter the correct current password.");
} }
} else {
res.status(403).json({error: "Access denied."});
} }
else res.status(403).json({error: ""});
}); });
router.put('/:user_id/confirm', (req, res) => { router.put('/:user_id/confirm', (req, res) => {
...@@ -253,13 +259,6 @@ router.post('/:user_id/avatar', (req, res, next) => { ...@@ -253,13 +259,6 @@ router.post('/:user_id/avatar', (req, res, next) => {
}); });
}); });
router.post('/feedback', function(req, res, next) {
var text = req.body.text;
// FIXME
mailer.sendMail("support@example.org", "Support Request by " + req.user.email, text, {reply_to: req.user.email});
res.sendStatus(201);
});
router.post('/password_reset_requests', (req, res, next) => { router.post('/password_reset_requests', (req, res, next) => {
const email = req.query.email; const email = req.query.email;
db.User.findOne({where: {"email": email}}).then((user) => { db.User.findOne({where: {"email": email}}).then((user) => {
...@@ -289,15 +288,10 @@ router.post('/password_reset_requests/:confirm_token/confirm', function(req, res ...@@ -289,15 +288,10 @@ router.post('/password_reset_requests/:confirm_token/confirm', function(req, res
if (user) { if (user) {
bcrypt.genSalt(10, (err, salt) => { bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(password, salt, function(err, hash) { bcrypt.hash(password, salt, function(err, hash) {
user.password_hash = hash; user.password_hash = hash;
user.password_token = null; user.password_token = null;
user.save(function(err, updatedUser){ user.save().then(function(updatedUser) {
if (err) { res.sendStatus(201);
res.sendStatus(400);
} else {
res.sendStatus(201);
}
}); });
}); });
}); });
...@@ -315,19 +309,4 @@ router.post('/:user_id/confirm', function(req, res, next) { ...@@ -315,19 +309,4 @@ router.post('/:user_id/confirm', function(req, res, next) {
res.sendStatus(201); res.sendStatus(201);
}); });
router.get('/:user_id/importables', function(req, res, next) {
glob('*.zip', function(err, files) {
res.status(200).json(files);
});
});
router.get('/:user_id/import', function(req, res, next) {
if (req.query.zip) {
res.send("importing");
importer.importZIP(req.user, req.query.zip);
} else {
res.sendStatus(400);
}
});
module.exports = router; module.exports = router;
...@@ -9,13 +9,157 @@ const router = express.Router(); ...@@ -9,13 +9,157 @@ const router = express.Router();
const mailer = require('../helpers/mailer'); const mailer = require('../helpers/mailer');
const _ = require('underscore'); const _ = require('underscore');
const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const passport = require('passport')
const Saml2js = require('saml2js');
const db = require('../models/db'); const db = require('../models/db');
const Sequelize = require('sequelize'); const Sequelize = require('sequelize');
const Op = Sequelize.Op; const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4'); const uuidv4 = require('uuid/v4');
// =========== PASSPORT =======
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
var samlStrategy = new SamlStrategy({
// URL that goes from the Identity Provider -> Service Provider
callbackUrl: config.path,
entryPoint: config.entryPoint,
issuer: config.issuer,
identifierFormat: null,
validateInResponseTo: false,
disableRequestedAuthnContext: true
},
function (profile, done) {
return done(null, {
id: profile.nameID,
idFormat: profile.nameIDFormat,
email: profile.email,
firstName: profile.givenName,
lastName: profile.sn
});
});
passport.use(samlStrategy);
// to generate Service Provider's XML metadata
router.get('/saml/metadata',
function(req, res) {
res.type('application/xml');
var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync('/cert/certificate.pem', 'utf8'));
res.status(200).send(spMetadata);
}
);
router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: '/login', failureFlash: true}), function(req, res){
const xmlResponse = req.body.SAMLResponse;
const parser = new Saml2js(xmlResponse);
const response = parser.toObject();
const email = response["mail"];
console.log(parser.toJSON());
console.log("Nickname "+ response["givenName"])
const nickname = response["givenName"];
//check, if user exists, if not create.
db.User.findAll({where: {email: email}})
.then(users => {
if (users.length == 0) {
crypto.randomBytes(16, function(ex, buf) {
var token = buf.toString('hex');
var u = {
_id: uuidv4(),
email: email,
account_type: "email",
nickname: nickname,
password_hash: "00000",
prefs_language: req.i18n.locale,
confirmation_token: token
};
db.User.create(u)
.error(err => {
res.sendStatus(400);
})
.then(u => {
var homeFolder = {
_id: uuidv4(),
name: req.i18n.__("home"),
space_type: "folder",
creator_id: u._id
};
db.Space.create(homeFolder)
.error(err => {
res.sendStatus(400);
})
.then(homeFolder => {
u.home_folder_id = homeFolder._id;
u.save()
.then(() => {
// home folder created,
// auto accept pending invites
db.Membership.update({
"state": "active"
}, {
where: {
"email_invited": u.email,
"state": "pending"
}
});
res.status(201).json({});
})
.error(err => {
res.status(400).json(err);
});
})
});
});
}
}).then(user =>{
db.User.findOne({where: {email: email}})
.error(err => {
res.sendStatus(404);
})
.then(user => {
crypto.randomBytes(48, function(ex, buf) {
var token = buf.toString('hex');
var session = {
user_id: user._id,
token: token,
ip: req.ip,
device: "web",
created_at: new Date(),
url : "/"
};
db.Session.create(session)
.error(err => {
console.error("Error creating Session:",err);
res.redirect(500, "/");
})
.then(() => {
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
console.log("session set successfully");
res.cookie('sdsession', token, { domain: domain, httpOnly: true });
res.redirect(302, "/")
});
});
});
});
});
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.render('index', { title: 'Spaces' }); res.render('index', { config:config, user:req.user });
}); });
router.get('/ping', (req, res) => { router.get('/ping', (req, res) => {
...@@ -23,39 +167,35 @@ router.get('/ping', (req, res) => { ...@@ -23,39 +167,35 @@ router.get('/ping', (req, res) => {
}); });
router.get('/spaces', (req, res) => { router.get('/spaces', (req, res) => {
res.render('spacedeck', { title: 'Spaces' }); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/not_found', (req, res) => { router.get('/not_found', (req, res) => {
res.render('not_found', { title: 'Spaces' }); res.render('not_found', {});
}); });
router.get('/confirm/:token', (req, res) => { router.get('/confirm/:token', (req, res) => {
res.render('spacedeck', { title: 'Space' }); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/folders/:id', (req, res) => { router.get('/folders/:id', (req, res) => {
res.render('spacedeck', {}); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/signup', (req, res) => { router.get('/signup', (req, res) => {
res.render('spacedeck', {}); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/accept/:id', (req, res) => { router.get('/accept/:id', (req, res) => {
res.render('spacedeck', {}); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/password-reset', (req, res) => { router.get('/password-reset', (req, res) => {
res.render('spacedeck', { title: 'Signup' }); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/password-confirm/:token', (req, res) => { router.get('/password-confirm/:token', (req, res) => {
res.render('spacedeck', { title: 'Signup' }); res.render('spacedeck', { config:config, user:req.user });
});
router.get('/team', (req, res) => {
res.render('spacedeck');
}); });
router.get('/de/*', (req, res) => { router.get('/de/*', (req, res) => {
...@@ -74,44 +214,39 @@ router.get('/fr', (req, res) => { ...@@ -74,44 +214,39 @@ router.get('/fr', (req, res) => {
res.redirect("/t/fr"); res.redirect("/t/fr");
}); });
router.get('/en/*', (req, res) => { router.get('/oc/*', (req, res) => {
res.redirect("/t/en"); res.redirect("/t/oc");
}); });
router.get('/en', (req, res) => { router.get('/oc', (req, res) => {
res.redirect("/t/end"); res.redirect("/t/oc");
}); });
router.get('/it', (req, res) => { router.get('/en/*', (req, res) => {
res.redirect("/t/en"); res.redirect("/t/en");
}); });
router.get('/account', (req, res) => { router.get('/en', (req, res) => {
res.render('spacedeck'); res.redirect("/t/end");
});
router.get('/login', (req, res) => {
res.render('spacedeck');
}); });
router.get('/logout', (req, res) => { router.get('/account', (req, res) => {
res.render('spacedeck'); res.render('spacedeck');
}); });
router.get('/contact', (req, res) => { router.get('/login', passport.authenticate('saml',
res.render('public/contact'); {
}); successRedirect: '/',
failureRedirect: '/login'
})
);
router.get('/about', (req, res) => {
res.render('public/about');
});
router.get('/terms', (req, res) => { // res.render('spacedeck', { config:config, user:req.user });
res.render('public/terms'); //});
});
router.get('/privacy', (req, res) => { router.get('/logout', (req, res) => {
res.render('public/privacy'); res.render('spacedeck', { config:config, user:req.user });
}); });
router.get('/t/:id', (req, res) => { router.get('/t/:id', (req, res) => {
...@@ -123,31 +258,31 @@ router.get('/t/:id', (req, res) => { ...@@ -123,31 +258,31 @@ router.get('/t/:id', (req, res) => {
res.redirect(path); res.redirect(path);
}); });
router.get('/s/:token', (req, res) => { router.get('/s/:hash', (req, res) => {
var token = req.params.token; var hash = req.params.hash;
if (token.split("-").length > 0) { if (hash.split("-").length > 0) {
token = token.split("-")[0]; hash = hash.split("-")[0];
} }
db.Space.findOne({where: {"edit_hash": token}}).then(function (space) { db.Space.findOne({where: {"edit_hash": hash}}).then(function (space) {
if (space) { if (space) {
if (req.accepts('text/html')){ if (req.accepts('text/html')){
res.redirect("/spaces/"+space._id + "?spaceAuth=" + token); res.redirect("/spaces/"+space._id + "?spaceAuth=" + hash);
} else { } else {
res.status(200).json(space); res.status(200).json(space);
} }
} else { } else {
if (req.accepts('text/html')) { if (req.accepts('text/html')) {
res.status(404).render('not_found', { title: 'Page Not Found.' }); res.status(404).render('not_found', {});
} else { } else {
res.status(404).json({}); res.status(404).json({});
} }
} }
}); });
}); });
router.get('/spaces/:id', (req, res) => { router.get('/spaces/:id', (req, res) => {
res.render('spacedeck', { title: 'Space' }); res.render('spacedeck', { config:config, user:req.user });
}); });
module.exports = router; module.exports = {router: router, passport:passport};
...@@ -16,37 +16,29 @@ const logger = require('morgan'); ...@@ -16,37 +16,29 @@ const logger = require('morgan');
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
const swig = require('swig');
const i18n = require('i18n-2'); const i18n = require('i18n-2');
const helmet = require('helmet'); const helmet = require('helmet');
const express = require('express'); const express = require('express');
const app = express(); const app = express();
const serveStatic = require('serve-static'); const serveStatic = require('serve-static');
const isProduction = app.get('env') === 'production'; const isProduction = app.get('env') === 'production';
// workaround for libssl_conf.so error triggered by phantomjs
process.env['OPENSSL_CONF'] = '/dev/null';
console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")"); console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")");
app.use(logger(isProduction ? 'combined' : 'dev')); app.use(logger(isProduction ? 'combined' : 'dev'));
i18n.expressBind(app, { i18n.expressBind(app, {
locales: ["en", "de", "fr"], locales: ["en", "de", "fr", "oc", "es"],
defaultLocale: "en", defaultLocale: "en",
cookieName: "spacedeck_locale", cookieName: "spacedeck_locale",
devMode: (app.get('env') == 'development') devMode: (app.get('env') == 'development')
}); });
swig.setDefaults({ app.set('view engine', 'ejs');
varControls: ["[[", "]]"] // otherwise it's not compatible with vue.js
});
swig.setFilter('cdn', function(input, idx) {
return input;
});
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
if (isProduction) { if (isProduction) {
app.set('views', path.join(__dirname, 'build', 'views')); app.set('views', path.join(__dirname, 'build', 'views'));
...@@ -68,18 +60,18 @@ app.use(bodyParser.urlencoded({ ...@@ -68,18 +60,18 @@ app.use(bodyParser.urlencoded({
})); }));
app.use(cookieParser()); app.use(cookieParser());
app.use(helmet.frameguard()) //app.use(helmet.frameguard())
app.use(helmet.xssFilter()) //app.use(helmet.xssFilter())
app.use(helmet.hsts({ /*app.use(helmet.hsts({
maxAge: 7776000000, maxAge: 7776000000,
includeSubdomains: true includeSubDomains: true
})) }))*/
app.disable('x-powered-by'); app.disable('x-powered-by');
app.use(helmet.noSniff()) //app.use(helmet.noSniff())
//app.use(require("./middlewares/error_helpers")); //app.use(require("./middlewares/error_helpers"));
app.use(require("./middlewares/session"));
//app.use(require("./middlewares/cors")); //app.use(require("./middlewares/cors"));
app.use(require("./middlewares/session"));
app.use(require("./middlewares/i18n")); app.use(require("./middlewares/i18n"));
app.use("/api", require("./middlewares/api_helpers")); app.use("/api", require("./middlewares/api_helpers"));
app.use('/api/spaces/:id', require("./middlewares/space_helpers")); app.use('/api/spaces/:id', require("./middlewares/space_helpers"));
...@@ -99,7 +91,7 @@ spaceRouter.use('/:id', require('./routes/api/space_exports')); ...@@ -99,7 +91,7 @@ spaceRouter.use('/:id', require('./routes/api/space_exports'));
app.use('/api/sessions', require('./routes/api/sessions')); app.use('/api/sessions', require('./routes/api/sessions'));
//app.use('/api/webgrabber', require('./routes/api/webgrabber')); //app.use('/api/webgrabber', require('./routes/api/webgrabber'));
app.use('/', require('./routes/root'));
if (config.get('storage_local_path')) { if (config.get('storage_local_path')) {
app.use('/storage', serveStatic(config.get('storage_local_path')+"/"+config.get('storage_bucket'), { app.use('/storage', serveStatic(config.get('storage_local_path')+"/"+config.get('storage_bucket'), {
...@@ -111,20 +103,27 @@ if (config.get('storage_local_path')) { ...@@ -111,20 +103,27 @@ if (config.get('storage_local_path')) {
//app.use(require('./middlewares/404')); //app.use(require('./middlewares/404'));
if (app.get('env') == 'development') { if (app.get('env') == 'development') {
app.set('view cache', false); app.set('view cache', false);
swig.setDefaults({cache: false});
} else { } else {
app.use(require('./middlewares/500')); app.use(require('./middlewares/500'));
} }
const root = require('./routes/root');
const passport = root.passport;
app.use(passport.initialize());
app.use(passport.session());
app.use('/', root.router);
module.exports = app; module.exports = app;
// CONNECT TO DATABASE // CONNECT TO DATABASE
db.init(); db.init();
// START WEBSERVER // START WEBSERVER
const port = 9666; const host = config.get('host');
const port = config.get('port');
const server = http.Server(app).listen(port, () => { const server = http.Server(app).listen(port, host, () => {
if ("send" in process) { if ("send" in process) {
process.send('online'); process.send('online');
......
...@@ -26,12 +26,12 @@ ...@@ -26,12 +26,12 @@
} }
} }
/*&.artifact-text.text-blank [contentEditable=true]:not(.text-editing) p:first-child::after { &.artifact-text.text-blank [contentEditable=true]:not(.text-editing) p:first-child::after {
content: "Double click to edit"; content: "Double click to edit";
opacity: 0.25; opacity: 0.25;
} }
&.artifact-text.text-blank [contentEditable=true].text-editing p:first-child::after { /*&.artifact-text.text-blank [contentEditable=true].text-editing p:first-child::after {
content: "Type here"; content: "Type here";
opacity: 0.25; opacity: 0.25;
}*/ }*/
...@@ -469,11 +469,10 @@ ...@@ -469,11 +469,10 @@
color: black; color: black;
//@include user-select(none); //@include user-select(none);
white-space: normal; white-space: normal;
font-size: 18px; font-size: 36px;
&.artifact-zone { &.artifact-zone {
border: 1px solid rgba(46,204,113,1); background-color: rgba(0,0,0,0.05);
background-color: rgba(46,204,113,0.025);
border-radius: 10px; border-radius: 10px;
&:after {display: none; } &:after {display: none; }
.shape {display: none; } .shape {display: none; }
...@@ -553,6 +552,10 @@ body:not(.present-mode) { ...@@ -553,6 +552,10 @@ body:not(.present-mode) {
cursor: grab !important; cursor: grab !important;
} }
.tool-note {
cursor: crosshair !important;
}
.artifact.state-idle { .artifact.state-idle {
.progress, .progress-text { .progress, .progress-text {
display: none; display: none;
......
...@@ -7,12 +7,6 @@ ...@@ -7,12 +7,6 @@
.btn-group.colors { .btn-group.colors {
.btn { .btn {
// padding: 4px;
// background-clip: content-box;
// padding-right: 2px;
// &:last-child {
// padding-right: 4px;
// }
box-shadow: inset 0 0 30px 0px rgba(40,40,40,0.1); box-shadow: inset 0 0 30px 0px rgba(40,40,40,0.1);
} }
} }
...@@ -64,7 +58,7 @@ ...@@ -64,7 +58,7 @@
backface-visibility: hidden; backface-visibility: hidden;
cursor: pointer; cursor: pointer;
background-color: $light; background-color: $light;
color: $medium;; color: $black;
@include user-select(none); @include user-select(none);
&:last-child {border: none;} &:last-child {border: none;}
...@@ -82,12 +76,9 @@ ...@@ -82,12 +76,9 @@
&.btn-link { &.btn-link {
background-color: transparent; background-color: transparent;
color: $medium;; color: $medium;
} }
&.facebook {background-color: $facebook !important; color: white !important;}
&.twitter {background-color: $twitter !important; color: white !important; }
&.btn-round { &.btn-round {
border-radius: 100px !important; border-radius: 100px !important;
} }
...@@ -96,21 +87,10 @@ ...@@ -96,21 +87,10 @@
border-radius: 6px !important; border-radius: 6px !important;
} }
// &.close {
// position: absolute;
// top: 15px;
// right: 15px;
// z-index: 4000;
// font-size: 40px;
// }
&.btn-nude { &.btn-nude {
min-width: 0 !important; min-width: 0 !important;
// font-size: inherit !important;
padding: 0 !important; padding: 0 !important;
// height: auto !important;
background-color: transparent; background-color: transparent;
color: $medium;
} }
&.btn-nude + .btn-nude { &.btn-nude + .btn-nude {
...@@ -123,7 +103,7 @@ ...@@ -123,7 +103,7 @@
&.btn-stroke { &.btn-stroke {
box-shadow: inset 0 0 0 1px $dark; box-shadow: inset 0 0 0 1px $dark;
color: $dark !important; color: $black;
background-color: transparent; background-color: transparent;
&:active { &:active {
box-shadow: inset 0 0 0 1px white; box-shadow: inset 0 0 0 1px white;
...@@ -132,9 +112,8 @@ ...@@ -132,9 +112,8 @@
} }
&.btn-stroke-darken { &.btn-stroke-darken {
//box-shadow: inset 0 0 0 1px rgba(0,0,0,0.1); border: 1px solid $black;
border: 1px solid rgba(0,0,0,0.1); color: $black;
color: $medium;
background-color: transparent; background-color: transparent;
&:active { &:active {
//box-shadow: inset 0 0 0 1px $dark; //box-shadow: inset 0 0 0 1px $dark;
...@@ -263,9 +242,18 @@ ...@@ -263,9 +242,18 @@
&.btn-transparent { &.btn-transparent {
background-color: transparent; background-color: transparent;
color: $medium; color: $dark;
&.active {color: $darker !important; } &.active {
&.open {color: white !important; } //color: $black !important;
color: $white;
background-color: $black;
}
&.open {
//color: $black !important;
color: $white;
background-color: $black;
border-radius: 0;
}
} }
&.btn-transparent-medium { &.btn-transparent-medium {
...@@ -313,7 +301,7 @@ ...@@ -313,7 +301,7 @@
&.btn-dark { &.btn-dark {
background-color: $dark ; background-color: $dark ;
color: $medium; color: $white;
} }
&.btn-medium { &.btn-medium {
...@@ -481,7 +469,6 @@ ...@@ -481,7 +469,6 @@
&.btn-icon { &.btn-icon {
padding: 0px !important; padding: 0px !important;
font-weight: bold;
max-width: 60px; max-width: 60px;
&.btn-xl { max-width: 80px; } &.btn-xl { max-width: 80px; }
...@@ -508,30 +495,6 @@ ...@@ -508,30 +495,6 @@
} }
} }
&.btn-social {
position: relative;
&:hover .icon,
.number {
@include scale(0,0);
opacity: 0;
}
&:hover .number {
@include transition( all 0.1s 0.1s ease-in-out);
@include scale(1,1);
opacity: 1;
}
.number,
.icon {
@include transition( all 0.1s 0s ease-in-out);
position: absolute;
top: 0;
left: 0;
}
}
&.btn-md.btn-icon-labeled { &.btn-md.btn-icon-labeled {
.icon:before { .icon:before {
line-height: 29px; line-height: 29px;
...@@ -567,7 +530,6 @@ ...@@ -567,7 +530,6 @@
.icon:before {line-height: 42px; } .icon:before {line-height: 42px; }
.icon-label { .icon-label {
font-size: 11px; font-size: 11px;
text-transform: capitalize;
text-align: center; text-align: center;
margin: 8px 0; margin: 8px 0;
display: block; display: block;
...@@ -580,7 +542,7 @@ ...@@ -580,7 +542,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
padding: 0 0px; padding: 0 0px;
font-weight: bold; font-weight: 300;
} }
&.hover { &.hover {
...@@ -714,7 +676,6 @@ ...@@ -714,7 +676,6 @@
} }
> * { > * {
border-radius: 0 !important;
background-clip: padding-box; background-clip: padding-box;
width: 100%; width: 100%;
float: left; float: left;
...@@ -775,7 +736,7 @@ ...@@ -775,7 +736,7 @@
} }
} }
.btn-group { .btn-group {
@include scale(0,0); //@include scale(0,0);
//@include transition( all 0.1s 0s ease-in-out); //@include transition( all 0.1s 0s ease-in-out);
position: absolute; position: absolute;
...@@ -787,7 +748,7 @@ ...@@ -787,7 +748,7 @@
margin-left: -12px; margin-left: -12px;
.btn { .btn {
@include scale(0,0); //@include scale(0,0);
//@include transition( all 0.1s 0.05s ease-in-out); //@include transition( all 0.1s 0.05s ease-in-out);
...@@ -979,31 +940,7 @@ ...@@ -979,31 +940,7 @@
} }
} }
.btn-group.bottom-left > .btn { // !btn-group
border-radius: 0px;
&:first-child{
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
&.last,
&:last-child{
border-top-right-radius: 3px;
border-bottom-right-radius: 0px;
}
}
.btn-xyz {
position: relative;
display: inline-block;
line-height: 0px;
padding: 0px;
font-size: 0px;
vertical-align: middle;
white-space: nowrap;
@include clearfix;
min-height: 44px;
}
.btn-group { .btn-group {
position: relative; position: relative;
...@@ -1014,13 +951,16 @@ ...@@ -1014,13 +951,16 @@
vertical-align: middle; vertical-align: middle;
white-space: nowrap; white-space: nowrap;
//border: 1px solid $dark;
border-radius: 5px;
&.dark { &.dark {
border-radius: $radius; border-radius: $radius;
background-color: $dark; background-color: $dark;
color: $lighter; color: $white;
.btn { .btn {
color: $lighter; color: $white;
} }
} }
...@@ -1159,4 +1099,4 @@ ...@@ -1159,4 +1099,4 @@
margin: 4px; margin: 4px;
z-index: 100; z-index: 100;
border-radius: 50px; border-radius: 50px;
} }
\ No newline at end of file
...@@ -96,41 +96,37 @@ ...@@ -96,41 +96,37 @@
border-bottom-right-radius: $radius*3; border-bottom-right-radius: $radius*3;
} }
.dialog-account {
width: 600px;
margin: auto;
margin-top: 100px;
}
.dialog { .dialog {
font-size: 13px;
ol, ul, p {
font-size: inherit;
}
> .btn-block:last-child { > .btn-block:last-child {
border-top-left-radius: 0px; border-top-left-radius: 0px;
border-top-right-radius: 0px; border-top-right-radius: 0px;
border-bottom-left-radius: $radius*3; border-bottom-left-radius: $radius*3;
border-bottom-right-radius: $radius*3; border-bottom-right-radius: $radius*3;
} }
min-width: 200px;
@include backface-visibility(hidden);
white-space: normal;
z-index: 1000;
position: absolute; position: absolute;
// white-space: normal; font-size: 15px;
border: 1px solid black;
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
border-radius: 5px;
white-space: normal;
opacity: 0; opacity: 0;
@include user-select(none); @include transition(all 0.125s ease-in-out);
@include transition( all 0.125s ease-in-out);
pointer-events: none; pointer-events: none;
background-color: $light; background-color: $light;
color: $medium; color: $dark;
&.dark {background-color: $dark; } &.dark {
background-color: $dark;
}
border-radius: $radius*3;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.05), 0 2px 7px rgba(0, 0, 0, 0.1);
.dialog-tabs-wrapper { .dialog-tabs-wrapper {
overflow: hidden; overflow: hidden;
border-top-left-radius: $radius*3; border-top-left-radius: $radius*3;
...@@ -150,15 +146,13 @@ ...@@ -150,15 +146,13 @@
&:hover span {color: $dark; } &:hover span {color: $dark; }
&.open span { &.open span {
background-color: $light; background-color: white;
color: $dark; color: $dark;
opacity: 1; opacity: 1;
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.05), 0 2px 7px rgba(0, 0, 0, 0.1) !important;
border-bottom-right-radius: 0px !important; border-bottom-right-radius: 0px !important;
border-bottom-left-radius: 0px !important; border-bottom-left-radius: 0px !important;
border-top-left-radius: $radius*3; border-top-left-radius: $radius*3;
border-top-right-radius: $radius*3; border-top-right-radius: $radius*3;
} }
&:first-child span { &:first-child span {
...@@ -200,7 +194,6 @@ ...@@ -200,7 +194,6 @@
text-align: center; text-align: center;
} }
.dialog-section { .dialog-section {
&:first-child {border: none !important; } &:first-child {border: none !important; }
border-top: 2px solid rgba(0,0,0,0.1); border-top: 2px solid rgba(0,0,0,0.1);
...@@ -228,4 +221,13 @@ ...@@ -228,4 +221,13 @@
h4 .icon { h4 .icon {
height: 38px; height: 38px;
} }
}
\ No newline at end of file // account dialog
&.dialog-freestanding {
margin: auto;
position: relative;
top: 150px;
border: none;
width: 800px;
}
}
...@@ -43,9 +43,6 @@ $predelay: 0; ...@@ -43,9 +43,6 @@ $predelay: 0;
&.hover:hover, &.hover:hover,
&.open { &.open {
// &:before {opacity: 0.125; }
// pointer-events: auto;
background-color: $dark;
background-color: $light; background-color: $light;
> * { > * {
...@@ -111,8 +108,8 @@ $predelay: 0; ...@@ -111,8 +108,8 @@ $predelay: 0;
} }
&:last-child > .btn{ &:last-child > .btn{
border-top-right-radius: $radius ; border-top-right-radius: $radius;
border-bottom-right-radius: $radius ; border-bottom-right-radius: $radius;
} }
} }
} }
...@@ -121,6 +118,10 @@ $predelay: 0; ...@@ -121,6 +118,10 @@ $predelay: 0;
display: inline-block; display: inline-block;
position: relative; position: relative;
vertical-align: middle; vertical-align: middle;
a {
text-decoration: none;
}
&.dropdown-block { &.dropdown-block {
display: block; display: block;
...@@ -143,8 +144,7 @@ $predelay: 0; ...@@ -143,8 +144,7 @@ $predelay: 0;
&.light > .dropdown-menu, &.light > .dropdown-menu,
&.light > .dialog { &.light > .dialog {
background: $light; background: white;
color: $medium;
} }
> .dropdown-menu { > .dropdown-menu {
...@@ -189,8 +189,6 @@ $predelay: 0; ...@@ -189,8 +189,6 @@ $predelay: 0;
} }
} }
&.hover:hover > .dialog, &.hover:hover > .dialog,
&.hover:hover > .dropdown-menu, &.hover:hover > .dropdown-menu,
...@@ -206,9 +204,7 @@ $predelay: 0; ...@@ -206,9 +204,7 @@ $predelay: 0;
&.open { &.open {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
-webkit-transform: translate3d(-50%, -50%, 100px) scale(1); //transform: translate3d(-50%, -50%, 100px) scale(1);
-ms-transform: translate3d(-50%, -50%, 100px) scale(1);
transform: translate3d(-50%, -50%, 100px) scale(1);
} }
} }
...@@ -217,10 +213,8 @@ $predelay: 0; ...@@ -217,10 +213,8 @@ $predelay: 0;
left: 50%; left: 50%;
top: 50%; top: 50%;
margin-top: 0px; margin-top: 0px;
@include transform-origin(center center); //@include transform-origin(center center);
-webkit-transform: translate3d(-50%, -50%, 100px) scale(0.93,0.8); //transform: translate3d(-50%, -50%, 100px) scale(0.93,0.8);
-ms-transform: translate3d(-50%, -50%, 100px) scale(0.93,0.8);
transform: translate3d(-50%, -50%, 100px) scale(0.93,0.8);
} }
} }
...@@ -230,10 +224,8 @@ $predelay: 0; ...@@ -230,10 +224,8 @@ $predelay: 0;
top: auto; top: auto;
bottom: 100%; bottom: 100%;
margin-bottom: 16px; margin-bottom: 16px;
@include transform-origin(bottom left); //@include transform-origin(bottom left);
-webkit-transform: translate3d(-33%, 0%, 100px) scale(0.93,0.8); //transform: translate3d(-33%, 0%, 100px) scale(0.93,0.8);
-ms-transform: translate3d(-33%, 0%, 100px) scale(0.93,0.8);
transform: translate3d(-33%, 0%, 100px) scale(0.93,0.8);
} }
} }
...@@ -243,10 +235,8 @@ $predelay: 0; ...@@ -243,10 +235,8 @@ $predelay: 0;
top: auto; top: auto;
bottom: 100%; bottom: 100%;
margin-bottom: 16px; margin-bottom: 16px;
@include transform-origin(bottom center); //@include transform-origin(bottom center);
-webkit-transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8); //transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
-ms-transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
} }
} }
...@@ -257,33 +247,37 @@ $predelay: 0; ...@@ -257,33 +247,37 @@ $predelay: 0;
top: 100%; top: 100%;
bottom: auto; bottom: auto;
margin-top: -16px; margin-top: -16px;
@include transform-origin(top center); //@include transform-origin(top center);
-webkit-transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8); //transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
-ms-transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8);
} }
} }
&.top.left {
> .dialog,
> .dropdown-menu {
left: 70px;
margin-top: -60px;
}
}
&.top.right { &.top.right {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
top: 100%; top: 100%;
bottom: auto; bottom: auto;
left: auto; left: auto;
right: 0;
margin-top: 16px; right: 70px;
@include transform-origin(top right); margin-top: -60px;
-webkit-transform: translate3d(0%, 0%, 100px) scale(0.93,0.8);
-ms-transform: translate3d(0%, 0%, 100px) scale(0.93,0.8); //@include transform-origin(top right);
transform: translate3d(0%, 0%, 100px) scale(0.93,0.8); //transform: translate3d(0%, 0%, 100px) scale(0.93,0.8);
} }
&.hover:hover, &.hover:hover,
&.open { &.open {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
-webkit-transform: translate3d(0%, 0%, 100px) scale(1); //transform: translate3d(0%, 0%, 100px) scale(1);
-ms-transform: translate3d(0%, 0%, 100px) scale(1);
transform: translate3d(0%, 0%, 100px) scale(1);
} }
} }
...@@ -312,9 +306,7 @@ $predelay: 0; ...@@ -312,9 +306,7 @@ $predelay: 0;
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
-webkit-transform: translate3d(-50%, 0%, 100px) scale(1); //transform: translate3d(-50%, 0%, 100px) scale(1);
-ms-transform: translate3d(-50%, 0%, 100px) scale(1);
transform: translate3d(-50%, 0%, 100px) scale(1);
} }
} }
} }
...@@ -324,9 +316,7 @@ $predelay: 0; ...@@ -324,9 +316,7 @@ $predelay: 0;
&.open { &.open {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
-webkit-transform: translate3d(-33%, 0%, 100px) scale(1) !important; //transform: translate3d(-33%, 0%, 100px) scale(1) !important;
-ms-transform: translate3d(-33%, 0%, 100px) scale(1) !important;
transform: translate3d(-33%, 0%, 100px) scale(1) !important;
} }
} }
} }
...@@ -334,7 +324,7 @@ $predelay: 0; ...@@ -334,7 +324,7 @@ $predelay: 0;
.dropdown { .dropdown {
&.options-3 { /*&.options-3 {
&.option-1:after { margin-left: -68px;} &.option-1:after { margin-left: -68px;}
&.option-2:after { margin-left: -8px;} &.option-2:after { margin-left: -8px;}
&.option-3:after { margin-left: 52px;} &.option-3:after { margin-left: 52px;}
...@@ -348,8 +338,9 @@ $predelay: 0; ...@@ -348,8 +338,9 @@ $predelay: 0;
-webkit-transform: scale(1); -webkit-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); transform: scale(1);
} }*/
/*
&:after { &:after {
@include transition( all 0.1s ease-in-out 0s); @include transition( all 0.1s ease-in-out 0s);
content: ""; content: "";
...@@ -362,26 +353,24 @@ $predelay: 0; ...@@ -362,26 +353,24 @@ $predelay: 0;
margin-left: -8px; margin-left: -8px;
pointer-events: none !important; pointer-events: none !important;
left: 50%; left: 50%;
-webkit-transform: scale(0,0); //transform: scale(0,0);
-ms-transform: scale(0,0);
transform: scale(0,0);
} }
&.bottom:after, &.bottomleft:after { &.bottom:after, &.bottomleft:after {
@include transform-origin(bottom center); //@include transform-origin(bottom center);
bottom: 100%; bottom: 100%;
border-bottom: 8px solid transparent; border-bottom: 8px solid transparent;
border-right: 8px solid transparent; border-right: 8px solid transparent;
border-top: 8px solid #303030; border-top: 8px solid #303030;
border-left: 8px solid transparent; border-left: 8px solid transparent;
} }
*/
&.top:after { /*&.top:after {
@include transform-origin(top center); @include transform-origin(top center);
top: 100%; top: 100%;
border-bottom: 8px solid #303030; border-bottom: 8px solid #303030;
border-right: 8px solid transparent; border-right: 8px solid transparent;
border-top: 8px solid transparent; border-top: 8px solid transparent;
border-left: 8px solid transparent; border-left: 8px solid transparent;
} }*/
} }
\ No newline at end of file
...@@ -254,7 +254,6 @@ ...@@ -254,7 +254,6 @@
// word-wrap: break-word; // word-wrap: break-word;
.item { .item {
box-shadow: 0 0 1pxrgba(0,0,0,0.1);
display: inline-block; display: inline-block;
text-align: left; text-align: left;
padding-right: $folder-gutter*2; padding-right: $folder-gutter*2;
...@@ -397,7 +396,10 @@ ...@@ -397,7 +396,10 @@
&:active { opacity: 0.95 !important; } &:active { opacity: 0.95 !important; }
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.025), 0 2px 7px rgba(0, 0, 0, 0.025); box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
border: 1px solid black;
// ???
@include opacity(1); @include opacity(1);
color: $medium; color: $medium;
// color: white; // color: white;
...@@ -476,7 +478,6 @@ ...@@ -476,7 +478,6 @@
left: 0px; left: 0px;
z-index: 100; z-index: 100;
width: auto; width: auto;
background-color: rgba(255,255,255,1);
.dropdown { .dropdown {
position: absolute; position: absolute;
...@@ -501,30 +502,6 @@ ...@@ -501,30 +502,6 @@
color: $dark; color: $dark;
text-align: left; text-align: left;
} }
.item-social {
padding: 8px;
border-right: 2px solid rgba(0,0,0,0.025);
@include clearfix;
color: $medium;
.item-likes,
.item-comments,
.item-shares {
position: relative;
&:hover {
.icon {opacity: 0; }
.number {opacity: 1; }
}
.number {
position: absolute;
opacity: 0;
top: 0;
left: 0;
}
.icon {opacity: 0.5; }
}
}
} }
.item-appendix { .item-appendix {
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
line-height: 1.5; line-height: 1.5;
width: 100%; width: 100%;
text-align: left; text-align: left;
color: $medium;
font-weight: normal; font-weight: normal;
cursor: pointer; cursor: pointer;
border-radius: $radius; border-radius: $radius;
...@@ -139,4 +138,4 @@ ...@@ -139,4 +138,4 @@
display: inline-block !important; display: inline-block !important;
width: auto !important; width: auto !important;
padding-right: 15px !important; padding-right: 15px !important;
} }
\ No newline at end of file
...@@ -2,24 +2,14 @@ ...@@ -2,24 +2,14 @@
@import "mixins"; @import "mixins";
.input-select { .input-select {
// background-color: rgba(255,255,255,0.04); background-color: rgba(255,255,255,0.04);
// background-image: url('images/select_arrow.gif'); background-image: url('images/select_arrow.gif');
border-radius: $radius; border-radius: $radius;
display: inline-block; display: inline-block;
width: 100%; width: 100%;
} }
@-moz-document url-prefix() {
select.input{
background-repeat: no-repeat;
background-position: right center;
cursor: pointer;
}
}
select { select {
-webkit-appearance:none;
// -moz-appearance:window;
appearance:none; appearance:none;
padding-left: 0px; padding-left: 0px;
width: 100%; width: 100%;
......
...@@ -23,7 +23,6 @@ input:invalid { ...@@ -23,7 +23,6 @@ input:invalid {
top: 0; top: 0;
right: 0; right: 0;
line-height: 1; line-height: 1;
font-size: 10px;
margin: 12px; margin: 12px;
color: red; color: red;
margin-right: 25px; margin-right: 25px;
...@@ -113,43 +112,26 @@ select { ...@@ -113,43 +112,26 @@ select {
&.input-white { &.input-white {
background-color: white; background-color: white;
color: $medium;
box-shadow: inset 0 0 1px 1px rgba(0, 0, 0, 0.05), inset 0 0px 4px rgba(0, 0, 0, 0.1); box-shadow: inset 0 0 1px 1px rgba(0, 0, 0, 0.05), inset 0 0px 4px rgba(0, 0, 0, 0.1);
} }
&.input-light { &.input-light {
background-color: $light; background-color: $light;
color: $medium;
} }
&.input-dark { &.input-dark {
background-color: $darker; background-color: $darker;
color: $medium;
} }
&.input-lighten { &.input-lighten {
background-color: rgba(255,255,255,0.05); background-color: rgba(255,255,255,0.05);
color: $medium !important;
} }
&.input-darken { &.input-darken {
background-color: rgba(0,0,0,0.05); background-color: rgba(0,0,0,0.05);
color: $medium;
} }
&.input-transparent { &.input-transparent {
background-color: transparent; background-color: transparent;
color: $medium;
}
// &:focus {color: white; }
&:invalid {
// background-color: rgba(198,101,84,0.05);
// color: rgba(198,101,84,0.75)
&:after {
}
} }
@include input-focus(); @include input-focus();
......
...@@ -69,26 +69,27 @@ ...@@ -69,26 +69,27 @@
} }
.handles { .handles {
// background-color: rgba(40,140,215,0.45); //border: 1px solid rgba(255,255,255,0.5);
border: 1px solid rgba(255,255,255,0.5);
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
bottom: 0; bottom: -1;
right: 0; right: 0;
z-index: 800; z-index: 800;
pointer-events: none; pointer-events: none;
background: rgba(255,255,255,0.1);
&:after{ &:after{
border: 1px dotted rgba(40,140,215,1); border: 4px dotted #000000;
content: ""; content: "";
display: block; display: block;
position: absolute; position: absolute;
height: auto; height: auto;
width: auto; width: auto;
top: -1px; top: 0px;
left: -1px; left: 0px;
right: -1px; right: 0px;
bottom: -1px; bottom: -1px;
} }
} }
...@@ -97,7 +98,7 @@ ...@@ -97,7 +98,7 @@
border: 8px solid rgba(255,255,255,0.5); border: 8px solid rgba(255,255,255,0.5);
&:after{ &:after{
border: 8px dotted rgba(40,140,215,1); border: 8px dotted #000000;
top: -4px; top: -4px;
left: -4px; left: -4px;
right: -4px; right: -4px;
...@@ -332,16 +333,15 @@ ...@@ -332,16 +333,15 @@
pointer-events:auto; pointer-events:auto;
z-index: 2000; z-index: 2000;
position: absolute; position: absolute;
width: 30px !important;
height: 30px !important;
border-radius: 100%; border-radius: 100%;
margin: -15px;
border: 1px solid rgba(0,0,0,0.25);
border: 1px solid black;
margin: -5px;
padding: 4px;
&:hover { &:hover {
background-color: rgba(255,255,255,0.5); background-color: black;
cursor: move; cursor: move;
} }
} }
...@@ -428,15 +428,8 @@ ...@@ -428,15 +428,8 @@
border-style: solid; border-style: solid;
border-width: 10px; border-width: 10px;
border-color: transparent; border-color: transparent;
-webkit-background-clip: padding-box; background-clip: padding-box;
-moz-background-clip: padding-box; transition: all .05s ease-in-out;
background-clip: padding-box;
-webkit-transition: all .05s ease-in-out;
-moz-transition: all .05s ease-in-out;
-ms-transition: all .05s ease-in-out;
-o-transition: all .05s ease-in-out;
transition: all .05s ease-in-out;
} }
div { div {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
.header-left, .header-left,
.header-right { .header-right {
position: absolute; position: absolute;
//@include transition( all 0.25s ease-in-out);
@include backface-visibility(hidden); @include backface-visibility(hidden);
z-index: 3000; z-index: 3000;
top: 10px; top: 10px;
...@@ -27,21 +26,21 @@ ...@@ -27,21 +26,21 @@
.home { .home {
margin-top: -20px; margin-top: -20px;
margin-left: -20px; margin-left: -20px;
// .icon {color: $dark; }
} }
.header-left { .header-left {
@include transform-origin(center left); left: 0;
left: 0; padding-left: 10px;
padding-left: 10px; padding-left: 20px;
padding-top: 20px;
} }
.header-right { .header-right {
@include transform-origin(center right); right: 0;
right: 0; padding-right: 20px;
padding-right: 10px; padding-top: 20px;
} }
.header-center { .header-center {
@include transform-origin(center center);
width: 100%; width: 100%;
left: 0; left: 0;
right: 0; right: 0;
...@@ -56,7 +55,7 @@ ...@@ -56,7 +55,7 @@
} }
} }
.header-left > * { margin-right: 10px; } .header-left > * { margin-right: 10px; }
.header-right > * { margin-left: 5px; } .header-right > * { margin-left: 10px; }
.header-right { font-size: 0;} .header-right { font-size: 0;}
.title { .title {
...@@ -90,21 +89,3 @@ ...@@ -90,21 +89,3 @@
opacity: 0.5; opacity: 0.5;
} }
} }
.present-mode #space-header {
background-color: transparent !important;
}
#space-siblings {
background-color: rgba(245, 245, 245, 0.95);
padding: 35px;
max-height: 450px;
overflow-y: scroll;
margin-top: 54px;
border-bottom: 1px solid #eee;
.btn {
margin-bottom: 50px;
}
}
...@@ -85,3 +85,12 @@ ...@@ -85,3 +85,12 @@
transform: rotateZ(45deg) translateX(-8px); transform: rotateZ(45deg) translateX(-8px);
} }
.icon-svg {
background-size: 26px;
background-position: center;
background-repeat: no-repeat;
}
.icon-sd6 {
background-image: url(/images/sd6-icon-white.svg);
}
@import "vars"; @import "vars";
#landing-header { #landing-header {
background-color: rgba(255,255,255,0.3); background-color: white;
height: 64px; height: 64px;
position: absolute; position: relative;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
} }
.landing-keyvisual-wrapper { #landing {
background-image: url("../images/sd5-keyvisual-compressed.jpg"); margin-top: 100px;
background-size: cover;
background-position: center; section {
padding-top: 40px; margin-left: 300px;
padding-bottom: 40px;
} > * {
max-width: 600px;
.landing-plans-wrapper { }
background-image: url("../images/sd5-hero2-compressed.jpg");
background-size: cover;
background-position: center;
padding-top: 80px;
padding-bottom: 100px;
}
.landing-box {
width: 800px;
margin: auto;
max-width: 90%;
background-color: white;
padding: 40px;
margin-bottom: 80px;
margin-top: 80px;
position: relative;
box-shadow: 0px 0px 50px rgba(0,0,0,0.2);
h1 {
margin-bottom: 20px;
}
&.black {
background-color: #222;
color: white;
padding: 20px;
text-align: center;
}
&.overlap {
position: absolute;
z-index: 2;
margin-top: -65px;
left: 50%;
top: 0px;
margin-left: -250px;
width: 500px;
}
&.screenshot {
width: 90%;
max-width: 90%;
padding: 20px;
box-shadow: none;
background-color: transparent;
img {
width: 100%;
position: absolute;
top: 0px;
left: 0px;
opacity: 0.3;
} }
}
&.landing-box-left {
margin-left: 30px;
}
}
.lead-xxl {
}
.lead {
margin-bottom: 20px;
}
.lead-xl {
}
.plans-box {
background: linear-gradient(to bottom, #FEFFFF 25%,#D0D8E2 100%);
padding: 40px;
border-radius: 9px;
}
.landing-box.plans-box {
margin-top: 200px;
width: 900px;
}
.plans-table {
tr {
vertical-align: top;
}
th {
font-size: 42px;
padding-top: 40px;
text-align: center;
}
th.best-plan {
padding-top: 20px;
font-size: 48px;
padding-bottom: 0px;
}
td {
padding: 20px;
width: 30%;
p, li {
font-size: 18px;
}
li {
margin-bottom: 10px;
}
}
td.best-plan {
width: 40%;
p {
font-size: 22px;
}
}
td li {
list-style-type: none;
text-align: center;
}
ul {
margin: 0 !important;
padding: 0 !important;
}
.upgrade-buttons {
text-align:center;
margin-top:20px;
}
}
.logo-row {
position: relative;
padding: 80px;
background-color: white;
text-align: center;
width: 100%;
&.blue {
background-color: $blue;
color: white;
}
}
.logo-row div {
display: inline-block;
width: 200px;
}
.landing-row {
background-color: white;
padding-bottom: 80px;
padding-top: 40px;
}
#keyvisual {
border-radius: 20px;
box-shadow: 0px 0px 20px #eee;
width: 640px;
height: 420px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
background-image: url('/images/landing/spacedeck-screenshot1.jpg');
background-color: white;
margin: auto;
margin-top: 40px;
margin-bottom: 40px;
border: 1px solid #eee;
}
#legal {
.landing-box {
width: 800px;
}
} }
.footer { .footer {
padding: 40px; margin-left: 300px;
padding-bottom: 80px; margin-top: 100px;
text-align: center; margin-bottom: 100px;
color: $medium;
a {
margin-right: 20px;
}
} }
@media screen and (max-width: 1000px) {
@media screen and (min-width: 801px) { #landing {
.plans-table-mobile { section {
display: none; margin-left: 20px;
} margin-right: 20px;
} }
@media screen and (max-width: 800px) {
ul.lead.lead-xl, p.lead.lead-xl, ol.lead.lead-xl {
font-size: 20px !important;
}
.header-right {
> span:first-child {
display: none;
} }
} .footer {
margin-left: 20px;
.plans-table { margin-right: 20px;
display: none;
}
.plans-table-mobile {
display: block;
tbody {
display: block;
width: 100%;
}
tr {
display: block;
width: 100%;
} }
td, th { .header-right {
display: block; right: auto;
width: 100%; padding-left: 10px;
padding-right: 20px;
padding-top: 80px;
} }
ul, li { #folder-wrapper {
width: 100%; padding-top: 128px;
} }
}
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
@import "mixins"; @import "mixins";
.wrapper { .wrapper {
//@include transition( all 0.25s ease-in-out);
position: relative; position: relative;
margin: auto; margin: auto;
max-width: 1160px; max-width: 1160px;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment