Compare commits

..

No commits in common. "whiteboard" and "kaleidos-issues/23/deleting-space-user-is-not-possible" have entirely different histories.

69 changed files with 2708 additions and 1442 deletions

2
.gitignore vendored
View File

@ -1,8 +1,6 @@
node_modules node_modules
javascripts/maps javascripts/maps
javascripts/spacedeck.js javascripts/spacedeck.js
public/stylesheets/*.css
database.sqlite
*.swp *.swp
*~ *~

View File

@ -1,13 +1,13 @@
const gulp = require('gulp') var gulp = require('gulp');
const sass = require('gulp-sass') var sass = require('gulp-sass');
const concat = require('gulp-concat') var concat = require('gulp-concat');
gulp.task('styles', function(done) { gulp.task('styles', function() {
gulp.src('styles/**/*.scss') gulp.src('styles/**/*.scss')
.pipe(sass({ .pipe(sass({
errLogToConsole: true errLogToConsole: true
})) }))
.pipe(gulp.dest('./public/stylesheets/')) .pipe(gulp.dest('./public/stylesheets/'))
.pipe(concat('style.css')) .pipe(concat('style.css'));
done() });
})

View File

@ -1,15 +1,15 @@
# Spacedeck Open # Spacedeck Open
![Spacedeck 6.0 Screenshot](/public/images/sd6-screenshot.png)
This is the free and open source version of Spacedeck, a web based, real time, collaborative whiteboard application with rich media support. Spacedeck was developed in 6 major releases during Autumn 2011 until the end of 2016 and was originally a commercial SaaS. The developers were Lukas F. Hartmann (mntmn) and Martin GĂĽther (magegu). This is the free and open source version of Spacedeck, a web based, real time, collaborative whiteboard application with rich media support. Spacedeck was developed in 6 major releases during Autumn 2011 until the end of 2016 and was originally a commercial SaaS. The developers were Lukas F. Hartmann (mntmn) and Martin GĂĽther (magegu).
The spacedeck.com online service was shut down on May 1st 2018. We decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted or local version. The spacedeck.com online service was shut down on May 1st 2018. We decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted or local version.
[MNT Research GmbH](https://mntre.com) has restarted development of Spacedeck Open in 2020.
We appreciate filed issues, pull requests and general discussion. We appreciate filed issues, pull requests and general discussion.
**Windows users:** Try the one-click release at https://github.com/spacedeck/spacedeck-open/releases/tag/v0.9
Desktop releases for Linux and Mac will be published here soon. In the meantime, you have to install Node.JS to run Spacedeck.
# Features # Features
- Create virtual whiteboards called *Spaces* with virtually unlimited size - Create virtual whiteboards called *Spaces* with virtually unlimited size
@ -17,23 +17,27 @@ We appreciate filed issues, pull requests and general discussion.
- Write and format text with full control over fonts, colors and style - Write and format text with full control over fonts, colors and style
- Draw, annotate and highlight with included graphical shapes - Draw, annotate and highlight with included graphical shapes
- Turn your Space into a zooming presentation - Turn your Space into a zooming presentation
- Collaborate in realtime with teammates, students or friends - Collaborate and chat in realtime with teammates, students or friends
- Share Spaces on the web or via email - Share Spaces on the web or via email
- Export your work as printable PDF or ZIP (currently being fixed, stay tuned) - Export your work as printable PDF or ZIP
# Use Cases # Data Import from Spacedeck.com
- Education: Virtual classwork with multimedia Spacedeck Open has a data import feature that you can use to migrate your ZIP export from Spacedeck.com.
- Creative: Mood boards, Brainstorming, Design Thinking
- Visual note taking and planning 1. Just copy your downloaded ZIP file into the spacedeck root folder. Don't extract it.
2. Start your local Spacedeck.
3. Navigate to *Account / Profile* (person icon in the top right corner).
4. Click the *Import* button next to the ZIP file name. It is on the bottom of the page.
5. Wait until console output has finished and you're done.
# Requirements, Installation # Requirements, Installation
Spacedeck requires: Spacedeck requires:
- Node.js 10.x: Web Server / API. Download: https://nodejs.org - Node.js 9.x: Web Server / API. Download: https://nodejs.org
To run Spacedeck, you only need Node.JS 10.x. To run Spacedeck, you only need Node.JS 9.x.
To install all node dependencies, run (do this once): To install all node dependencies, run (do this once):
@ -49,6 +53,10 @@ See [config/default.json](config/default.json)
Then open http://localhost:9666 in a web browser. Then open http://localhost:9666 in a web browser.
# Run (desktop app with integrated web server)
electron .
# Optional Dependencies # Optional Dependencies
For advanced media conversion: For advanced media conversion:

0
bin/www Normal file → Executable file
View File

View File

@ -1,11 +1,8 @@
{ {
"team_name": "My Open Spacedeck", //"endpoint": "http://localhost:9000",
"contact_email": "support@example.org",
"endpoint": "http://localhost:9666", "endpoint": "http://localhost:9666",
"invite_code": "", //disabled invite code by default
"storage_region": "eu-central-1", "storage_region": "eu-central-1",
//"storage_bucket": "sdeck-development", //"storage_bucket": "sdeck-development",
//"storage_cdn": "http://localhost:9123/sdeck-development", //"storage_cdn": "http://localhost:9123/sdeck-development",
//"storage_endpoint": "http://storage:9000", //"storage_endpoint": "http://storage:9000",
@ -21,14 +18,5 @@
"google_access" : "", "google_access" : "",
"google_secret" : "", "google_secret" : "",
"admin_pass": "very_secret_admin_password", "admin_pass": "very_secret_admin_password",
"phantom_api_secret": "very_secret_phantom_password", "phantom_api_secret": "very_secret_phantom_password"
// Choose "console" or "smtp"
"mail_provider": "smtp",
"mail_smtp_host": "your.smtp.host",
"mail_smtp_port": 465,
"mail_smtp_secure": true,
"mail_smtp_require_tls": true,
"mail_smtp_user": "your.smtp.user",
"mail_smtp_pass": "your.secret.smtp.password"
} }

View File

@ -1,17 +1,17 @@
# Windows Electron Build # Windows Electron Build
sqlite3 needs to be manually built for the iojs version that electron ships. The following code assumes electron v1.8.4. sqlite3 needs to be manually built for the iojs version that electron ships. The following code assumes electron v1.8.4.
```` ````
npm -g install windows-build-tools npm -g install windows-build-tools
cd node_modules\sqlite3 cd node_modules\sqlite3
node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64 node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64
node-gyp rebuild --target=1.8.4 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64 --msvs_version=2015 node-gyp rebuild --target=1.8.4 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64 --msvs_version=2015
cd ..\.. cd ..\..
```` ````

View File

@ -1,18 +1,18 @@
'use strict'; 'use strict';
const config = require('config'); var swig = require('swig');
const nodemailer = require('nodemailer');
const swig = require('swig');
//var AWS = require('aws-sdk'); //var AWS = require('aws-sdk');
module.exports = { module.exports = {
sendMail: (to_email, subject, body, options) => { sendMail: (to_email, subject, body, options) => {
if (!options) { if (!options) {
options = {}; options = {};
} }
const teamname = options.teamname || config.get('team_name'); // FIXME
const from = teamname + ' <' + config.get('contact_email') + '>'; const teamname = options.teamname || "My Open Spacedeck"
const from = teamname + ' <support@example.org>';
let reply_to = [from]; let reply_to = [from];
if (options.reply_to) { if (options.reply_to) {
@ -29,38 +29,33 @@ module.exports = {
options: options options: options
}); });
if (config.get('mail_provider') === 'console') { //if (process.env.NODE_ENV === 'development') {
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + htmlText + "\n\n plaintext:\n" + plaintext); console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + htmlText + "\n\n plaintext:\n" + plaintext);
/*} else {
AWS.config.update({region: 'eu-west-1'});
var ses = new AWS.SES();
} else if (config.get('mail_provider') === 'smtp') { ses.sendEmail( {
Source: from,
const transporter = nodemailer.createTransport({ Destination: { ToAddresses: [to_email] },
host: config.get('mail_smtp_host'), ReplyToAddresses: reply_to,
port: config.get('mail_smtp_port'), Message: {
secure: config.get('mail_smtp_secure'), Subject: {
requireTLS: config.get('mail_smtp_require_tls'), Data: subject
auth: { },
user: config.get('mail_smtp_user'), Body: {
pass: config.get('mail_smtp_pass'), Text: {
Data: plaintext,
},
Html: {
Data: htmlText
}
}
} }
}, function(err, data) {
if (err) console.error("Error sending email:", err);
else console.log("Email sent.");
}); });
}*/
transporter.sendMail({
from: from,
replyTo: reply_to,
to: to_email,
subject: subject,
text: plaintext,
html: htmlText,
}, function(err, info) {
if (err) {
console.error("Error sending email:", err);
} else {
console.log("Email sent.");
}
});
}
} }
}; };

View File

@ -57,6 +57,11 @@ module.exports = (req, res, next) => {
"_id": spaceId "_id": spaceId
}}).then(function(space) { }}).then(function(space) {
//.populate("creator", userMapping)
//if (err) {
// res.status(400).json(err);
//} else {
if (space) { if (space) {
if (space.access_mode == "public") { if (space.access_mode == "public") {
if (space.password) { if (space.password) {

View File

@ -91,8 +91,7 @@ module.exports = {
user_id: Sequelize.STRING, user_id: Sequelize.STRING,
role: Sequelize.STRING, role: Sequelize.STRING,
code: Sequelize.STRING, code: Sequelize.STRING,
state: {type: Sequelize.STRING, defaultValue: "pending"}, // valid: "pending", "active" state: {type: Sequelize.STRING, defaultValue: "pending"},
email_invited: Sequelize.STRING,
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW} updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
}), }),
@ -279,20 +278,21 @@ module.exports = {
getUserRoleInSpace: (originalSpace, user, cb) => { getUserRoleInSpace: (originalSpace, user, cb) => {
originalSpace.path = []; originalSpace.path = [];
console.log("getUserRoleInSpace",originalSpace._id,user._id,user.home_folder_id);
if (originalSpace._id == user.home_folder_id || (originalSpace.creator_id && originalSpace.creator_id == user._id)) { if (originalSpace._id == user.home_folder_id || (originalSpace.creator_id && originalSpace.creator_id == user._id)) {
cb("admin"); cb("admin");
} else { } else {
var findMembershipsForSpace = function(space, allMemberships, prevRole) { var findMembershipsForSpace = function(space, allMemberships, prevRole) {
Membership.findAll({ where: { Membership.findAll({ where: {
"space_id": space._id "space": space._id
}}).then(function(parentMemberships) { }}).then(function(parentMemberships) {
var currentMemberships = parentMemberships.concat(allMemberships); var currentMemberships = parentMemberships.concat(allMemberships);
if (space.parent_space_id) { if (space.parent_space_id) {
Space.findOne({ where: { Space.findOne({ where: {
"_id": space.parent_space_id "_id": space.parent_space_id
}}).then(function(parentSpace) { }}, function(err, parentSpace) {
findMembershipsForSpace(parentSpace, currentMemberships, prevRole); findMembershipsForSpace(parentSpace, currentMemberships, prevRole);
}); });
} else { } else {

View File

@ -2,7 +2,7 @@
module.exports = { module.exports = {
up: function(migration, DataTypes) { up: function(migration, DataTypes) {
return Promise.all([ return [
migration.changeColumn('memberships', 'space_id', migration.changeColumn('memberships', 'space_id',
{ {
type: DataTypes.STRING, type: DataTypes.STRING,
@ -36,11 +36,11 @@ module.exports = {
onUpdate: 'CASCADE' onUpdate: 'CASCADE'
} }
) )
]) ]
}, },
down: function(migration, DataTypes) { down: function(migration, DataTypes) {
return Promise.all([ return [
migration.changeColumn('memberships', 'space_id', migration.changeColumn('memberships', 'space_id',
{ {
type: DataTypes.STRING, type: DataTypes.STRING,
@ -52,6 +52,7 @@ module.exports = {
onUpdate: 'NO ACTION' onUpdate: 'NO ACTION'
} }
), ),
,
migration.changeColumn('artifacts', 'space_id', migration.changeColumn('artifacts', 'space_id',
{ {
type: DataTypes.STRING, type: DataTypes.STRING,
@ -74,6 +75,6 @@ module.exports = {
onUpdate: 'NO ACTION' onUpdate: 'NO ACTION'
} }
) )
]) ]
} }
} };

View File

@ -3,52 +3,48 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node spacedeck.js" "start": "electron ."
}, },
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=7.8.0"
}, },
"dependencies": { "dependencies": {
"archiver": "1.3.0", "archiver": "1.3.0",
"async": "2.3.0", "async": "2.3.0",
"basic-auth": "1.1.0", "basic-auth": "1.1.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "^1.19.0", "body-parser": "~1.17.1",
"cheerio": "0.22.0", "cheerio": "0.22.0",
"config": "1.25.1", "config": "1.25.1",
"cookie-parser": "~1.4.3", "cookie-parser": "~1.4.3",
"electron": "^1.8.4",
"execSync": "latest", "execSync": "latest",
"express": "^4.16.4", "express": "~4.13.0",
"file-type": "^7.6.0", "file-type": "^7.6.0",
"glob": "7.1.1", "glob": "7.1.1",
"gm": "^1.23.1", "gm": "1.23.0",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-sass": "^4.0.2",
"helmet": "^3.5.0", "helmet": "^3.5.0",
"i18n-2": "0.6.3", "i18n-2": "0.6.3",
"log-timestamp": "latest", "log-timestamp": "latest",
"mock-aws-s3": "^2.6.0", "mock-aws-s3": "^2.6.0",
"moment": "^2.19.3", "moment": "^2.19.3",
"morgan": "^1.9.1", "morgan": "1.8.1",
"node-phantom-simple": "2.2.4", "node-phantom-simple": "2.2.4",
"node-server-screenshot": "^0.2.1", "phantomjs-prebuilt": "2.1.14",
"nodemailer": "^4.6.7",
"phantomjs-prebuilt": "^2.1.16",
"read-chunk": "^2.1.0", "read-chunk": "^2.1.0",
"request": "^2.88.0", "request": "2.81.0",
"sanitize-html": "^1.11.1", "sanitize-html": "^1.11.1",
"sequelize": "^4.37.6", "sequelize": "^4.37.6",
"serve-favicon": "~2.4.2", "serve-favicon": "~2.4.2",
"serve-static": "^1.13.1", "serve-static": "^1.13.1",
"slug": "^1.1.0", "slug": "0.9.1",
"sqlite3": "^4.0.0", "sqlite3": "^4.0.0",
"swig": "1.4.2", "swig": "1.4.2",
"umzug": "^2.1.0", "umzug": "^2.1.0",
"underscore": "1.8.3", "underscore": "1.8.3",
"uuid": "^3.2.1", "uuid": "^3.2.1",
"validator": "7.0.0", "validator": "7.0.0",
"ws": "3.3.1" "ws": "2.2.3"
}, },
"main": "app.js", "main": "app.js",
"description": "", "description": "",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="17.370329mm"
height="17.370247mm"
viewBox="0 0 17.370329 17.370247"
version="1.1"
id="svg3417"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="sd6-icon-white.svg"
inkscape:export-filename="/home/mntmn/code/spacedeck-open/public/images/favicon.png"
inkscape:export-xdpi="93.585312"
inkscape:export-ydpi="93.585312">
<defs
id="defs3411" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="68.901329"
inkscape:cy="26.613846"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata3414">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-61.618407,-79.672019)">
<path
inkscape:connector-curvature="0"
id="path1681-6-5-3-7-4-9-2-0-2-9-7"
d="m 69.103371,79.69206 c -0.792105,0.07526 -1.553632,0.368078 -2.179688,0.99414 -0.967242,0.967233 -1.023215,2.24006 -0.822265,3.46875 -1.228429,-0.200703 -2.499819,-0.144769 -3.466797,0.822266 -1.252082,1.252133 -1.178244,3.043412 -0.677734,4.544922 0.500509,1.50151 1.477937,2.995513 2.832031,4.349611 1.354102,1.3541 2.848091,2.33152 4.349609,2.83203 1.501518,0.50051 3.292795,0.57437 4.544922,-0.67773 0.9673,-0.96727 1.023249,-2.24001 0.822266,-3.468755 1.228416,0.200714 2.499803,0.146691 3.466796,-0.820313 1.252124,-1.252112 1.17824,-3.045353 0.677735,-4.546874 -0.500505,-1.501522 -1.477926,-2.995502 -2.832031,-4.34961 -1.354109,-1.354105 -2.848087,-2.329573 -4.34961,-2.830078 -0.750761,-0.250253 -1.57313,-0.393617 -2.365234,-0.318359 z m 0.251953,3.427734 c -0.06232,0.06232 0.187775,-0.12686 1.025391,0.152344 0.837615,0.279204 1.980359,0.976455 3.005859,2.001953 1.025498,1.0255 1.720796,2.16629 2,3.003906 0.279204,0.837616 0.09198,1.087707 0.154297,1.025391 0.06232,-0.06232 -0.187775,0.124907 -1.025391,-0.154297 -0.817005,-0.272334 -1.926016,-0.966798 -2.93164,-1.951172 -0.02107,-0.02133 -0.03343,-0.04515 -0.05469,-0.06641 -0.02194,-0.02194 -0.04635,-0.0349 -0.06836,-0.05664 -0.984356,-1.005615 -1.678841,-2.112692 -1.951172,-2.929687 -0.279204,-0.837616 -0.09198,-1.087708 -0.154297,-1.025391 z m -4.289063,4.289063 c -0.06231,0.06232 0.187774,-0.124903 1.025391,0.154296 0.81575,0.271911 1.923337,0.965368 2.927735,1.947266 0.02276,0.02306 0.03561,0.04929 0.05859,0.07227 0.023,0.023 0.04918,0.03581 0.07227,0.05859 0.981898,1.004395 1.67535,2.111982 1.947265,2.927735 0.279205,0.837619 0.09198,1.087705 0.154297,1.025385 0.06232,-0.0623 -0.187772,0.12492 -1.02539,-0.154291 -0.837619,-0.27921 -1.980364,-0.974504 -3.00586,-2 -1.025488,-1.025491 -1.720791,-2.168245 -2,-3.00586 -0.279208,-0.837615 -0.09198,-1.087708 -0.154297,-1.02539 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.4395833;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:37.79527664;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="17.370329mm"
height="17.370247mm"
viewBox="0 0 17.370329 17.370247"
version="1.1"
id="svg3417"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="sd6-icon.svg">
<defs
id="defs3411" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="68.901329"
inkscape:cy="26.613846"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata3414">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-61.618407,-79.672019)">
<path
inkscape:connector-curvature="0"
id="path1681-6-5-3-7-4-9-2-0-2-9-7"
d="m 69.103371,79.69206 c -0.792105,0.07526 -1.553632,0.368078 -2.179688,0.99414 -0.967242,0.967233 -1.023215,2.24006 -0.822265,3.46875 -1.228429,-0.200703 -2.499819,-0.144769 -3.466797,0.822266 -1.252082,1.252133 -1.178244,3.043412 -0.677734,4.544922 0.500509,1.50151 1.477937,2.995513 2.832031,4.349611 1.354102,1.3541 2.848091,2.33152 4.349609,2.83203 1.501518,0.50051 3.292795,0.57437 4.544922,-0.67773 0.9673,-0.96727 1.023249,-2.24001 0.822266,-3.468755 1.228416,0.200714 2.499803,0.146691 3.466796,-0.820313 1.252124,-1.252112 1.17824,-3.045353 0.677735,-4.546874 -0.500505,-1.501522 -1.477926,-2.995502 -2.832031,-4.34961 -1.354109,-1.354105 -2.848087,-2.329573 -4.34961,-2.830078 -0.750761,-0.250253 -1.57313,-0.393617 -2.365234,-0.318359 z m 0.251953,3.427734 c -0.06232,0.06232 0.187775,-0.12686 1.025391,0.152344 0.837615,0.279204 1.980359,0.976455 3.005859,2.001953 1.025498,1.0255 1.720796,2.16629 2,3.003906 0.279204,0.837616 0.09198,1.087707 0.154297,1.025391 0.06232,-0.06232 -0.187775,0.124907 -1.025391,-0.154297 -0.817005,-0.272334 -1.926016,-0.966798 -2.93164,-1.951172 -0.02107,-0.02133 -0.03343,-0.04515 -0.05469,-0.06641 -0.02194,-0.02194 -0.04635,-0.0349 -0.06836,-0.05664 -0.984356,-1.005615 -1.678841,-2.112692 -1.951172,-2.929687 -0.279204,-0.837616 -0.09198,-1.087708 -0.154297,-1.025391 z m -4.289063,4.289063 c -0.06231,0.06232 0.187774,-0.124903 1.025391,0.154296 0.81575,0.271911 1.923337,0.965368 2.927735,1.947266 0.02276,0.02306 0.03561,0.04929 0.05859,0.07227 0.023,0.023 0.04918,0.03581 0.07227,0.05859 0.981898,1.004395 1.67535,2.111982 1.947265,2.927735 0.279205,0.837619 0.09198,1.087705 0.154297,1.025385 0.06232,-0.0623 -0.187772,0.12492 -1.02539,-0.154291 -0.837619,-0.27921 -1.980364,-0.974504 -3.00586,-2 -1.025488,-1.025491 -1.720791,-2.168245 -2,-3.00586 -0.279208,-0.837615 -0.09198,-1.087708 -0.154297,-1.02539 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.4395833;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:37.79527664;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="81.731232mm"
height="17.370247mm"
viewBox="0 0 81.731232 17.370247"
version="1.1"
id="svg2651"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="sd6-logo-black.svg">
<defs
id="defs2645" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="80.852573"
inkscape:cy="-16.110417"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata2648">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-29.059958,-86.19285)">
<g
id="g3248">
<path
inkscape:connector-curvature="0"
id="path1681-6-5-3-7-4-9-2-0-2-9-7"
d="m 36.544922,86.212891 c -0.792105,0.07526 -1.553632,0.368078 -2.179688,0.99414 -0.967242,0.967233 -1.023215,2.24006 -0.822265,3.46875 -1.228429,-0.200703 -2.499819,-0.144769 -3.466797,0.822266 -1.252082,1.252133 -1.178244,3.043412 -0.677734,4.544922 0.500509,1.50151 1.477937,2.995513 2.832031,4.349611 1.354102,1.3541 2.848091,2.33152 4.349609,2.83203 1.501518,0.50051 3.292795,0.57437 4.544922,-0.67773 0.9673,-0.96727 1.023249,-2.24001 0.822266,-3.468755 1.228416,0.200714 2.499803,0.146691 3.466796,-0.820313 1.252124,-1.252112 1.17824,-3.045353 0.677735,-4.546874 -0.500505,-1.501522 -1.477926,-2.995502 -2.832031,-4.34961 -1.354109,-1.354105 -2.848087,-2.329573 -4.34961,-2.830078 -0.750761,-0.250253 -1.57313,-0.393617 -2.365234,-0.318359 z m 0.251953,3.427734 c -0.06232,0.06232 0.187775,-0.12686 1.025391,0.152344 0.837615,0.279204 1.980359,0.976455 3.005859,2.001953 1.025498,1.0255 1.720796,2.16629 2,3.003906 0.279204,0.837616 0.09198,1.087707 0.154297,1.025391 0.06232,-0.06232 -0.187775,0.124907 -1.025391,-0.154297 -0.817005,-0.272334 -1.926016,-0.966798 -2.93164,-1.951172 -0.02107,-0.02133 -0.03343,-0.04515 -0.05469,-0.06641 -0.02194,-0.02194 -0.04635,-0.0349 -0.06836,-0.05664 -0.984356,-1.005615 -1.678841,-2.112692 -1.951172,-2.929687 -0.279204,-0.837616 -0.09198,-1.087708 -0.154297,-1.025391 z m -4.289063,4.289063 c -0.06231,0.06232 0.187774,-0.124903 1.025391,0.154296 0.81575,0.271911 1.923337,0.965368 2.927735,1.947266 0.02276,0.02306 0.03561,0.04929 0.05859,0.07227 0.023,0.023 0.04918,0.03581 0.07227,0.05859 0.981898,1.004395 1.67535,2.111982 1.947265,2.927735 0.279205,0.837619 0.09198,1.087705 0.154297,1.025385 0.06232,-0.0623 -0.187772,0.12492 -1.02539,-0.154291 -0.837619,-0.27921 -1.980364,-0.974504 -3.00586,-2 -1.025488,-1.025491 -1.720791,-2.168245 -2,-3.00586 -0.279208,-0.837615 -0.09198,-1.087708 -0.154297,-1.02539 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.4395833;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:37.79527664;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
id="g2614"
transform="matrix(0.26458333,0,0,0.26458333,-523.78744,61.714265)">
<g
id="flowRoot1610-0-6-8-1-1"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;line-height:1.25;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.37800002;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:37.79527664;stroke-opacity:1"
transform="matrix(2.6369365,0,0,2.6369365,2045.0224,86.079903)"
aria-label="Spacedeck">
<path
id="path3214"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 52.795627,11.002199 h 2.693247 C 55.466146,8.82601 53.73315,7.3543837 51.028539,7.3543837 c -2.659155,0 -4.573974,1.4488985 -4.556928,3.6137233 -0.0057,1.767088 1.232985,2.76143 3.244397,3.221669 l 1.215938,0.284097 c 1.27844,0.295462 1.852317,0.642061 1.863681,1.295486 -0.01136,0.710244 -0.676152,1.204575 -1.806861,1.204575 -1.244349,0 -2.06255,-0.57956 -2.125052,-1.698905 h -2.693246 c 0.03409,2.721656 1.926182,4.022824 4.852389,4.022824 2.897797,0 4.613748,-1.312532 4.625112,-3.522812 -0.01136,-1.857999 -1.267076,-2.99439 -3.562586,-3.500084 l -1.000024,-0.227278 c -1.056844,-0.227279 -1.727315,-0.57956 -1.704587,-1.272758 0.0057,-0.636379 0.55115,-1.0966177 1.642085,-1.0966177 1.096618,0 1.698905,0.4943297 1.77277,1.3238957 z"
inkscape:connector-curvature="0" />
<path
id="path3216"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 57.068458,22.422928 h 2.778476 v -4.687613 h 0.05682 c 0.352281,0.806838 1.136391,1.53981 2.454605,1.53981 1.931864,0 3.48872,-1.5114 3.48872,-4.483062 0,-3.07962 -1.647767,-4.483063 -3.471674,-4.483063 -1.380715,0 -2.136415,0.806838 -2.471651,1.607994 h -0.08523 v -1.494355 h -2.750066 z m 2.721656,-7.636547 c 0,-1.426171 0.590923,-2.306874 1.607993,-2.306874 1.028434,0 1.59663,0.903431 1.59663,2.306874 0,1.409125 -0.568196,2.323919 -1.59663,2.323919 -1.01707,0 -1.607993,-0.909112 -1.607993,-2.323919 z"
inkscape:connector-curvature="0" />
<path
id="path3218"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 69.778991,19.297853 c 1.215939,0 2.056868,-0.471602 2.534152,-1.363669 h 0.06818 v 1.215938 h 2.613699 v -5.931961 c 0,-1.846635 -1.642085,-2.909161 -3.86373,-2.909161 -2.346647,0 -3.676224,1.181847 -3.897821,2.772794 l 2.562562,0.09091 c 0.119321,-0.556832 0.579559,-0.897749 1.312532,-0.897749 0.681834,0 1.113663,0.329553 1.113663,0.914794 v 0.02841 c 0,0.534104 -0.57956,0.647743 -2.068232,0.778428 -1.767088,0.147731 -3.244396,0.801156 -3.244396,2.73302 0,1.727315 1.198892,2.568244 2.869387,2.568244 z m 0.857975,-1.818226 c -0.642061,0 -1.096617,-0.306825 -1.096617,-0.886384 0,-0.562514 0.443193,-0.903431 1.232984,-1.022752 0.517058,-0.07387 1.153437,-0.187505 1.465945,-0.352282 v 0.829566 c 0,0.852293 -0.715927,1.431852 -1.602312,1.431852 z"
inkscape:connector-curvature="0" />
<path
id="path3220"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 80.767893,19.314899 c 2.454605,0 3.977369,-1.426171 4.051234,-3.585314 h -2.596653 c -0.102275,0.926159 -0.659107,1.431853 -1.420489,1.431853 -0.977296,0 -1.613675,-0.823883 -1.613675,-2.375057 0,-1.53981 0.642061,-2.363693 1.613675,-2.363693 0.795474,0 1.312532,0.539785 1.420489,1.431852 h 2.596653 c -0.0625,-2.147779 -1.630721,-3.54554 -4.056916,-3.54554 -2.744384,0 -4.403515,1.82959 -4.403515,4.505791 0,2.664836 1.647767,4.500108 4.409197,4.500108 z"
inkscape:connector-curvature="0" />
<path
id="path3222"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 90.336304,19.314899 c 2.289828,0 3.795546,-1.107981 4.113736,-2.823932 l -2.551198,-0.07387 c -0.215914,0.579559 -0.78411,0.892067 -1.5114,0.892067 -1.068208,0 -1.727315,-0.710245 -1.727315,-1.778452 v -0.07386 h 5.818322 v -0.693199 c 0,-2.875069 -1.750042,-4.454653 -4.227374,-4.454653 -2.636427,0 -4.32965,1.806862 -4.32965,4.511473 0,2.795521 1.670495,4.494426 4.414879,4.494426 z m -1.676177,-5.471723 c 0.03977,-0.869339 0.727291,-1.528446 1.647767,-1.528446 0.914795,0 1.573902,0.636379 1.585266,1.528446 z"
inkscape:connector-curvature="0" />
<path
id="path3224"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 99.10072,19.275125 c 1.31821,0 2.10232,-0.732972 2.4546,-1.53981 h 0.0852 v 1.414807 h 2.75007 V 7.5134784 h -2.77848 v 4.4035156 h -0.0568 C 101.22577,11.115838 100.46439,10.309 99.089356,10.309 c -1.823907,0 -3.477356,1.403443 -3.477356,4.483063 0,2.971662 1.562537,4.483062 3.48872,4.483062 z m 0.96593,-2.164825 c -1.028432,0 -1.602309,-0.914794 -1.602309,-2.323919 0,-1.403443 0.568196,-2.306874 1.602309,-2.306874 1.01707,0 1.608,0.880703 1.608,2.306874 0,1.414807 -0.59661,2.323919 -1.608,2.323919 z"
inkscape:connector-curvature="0" />
<path
id="path3226"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 110.24303,19.314899 c 2.28983,0 3.79555,-1.107981 4.11374,-2.823932 l -2.5512,-0.07387 c -0.21591,0.579559 -0.78411,0.892067 -1.5114,0.892067 -1.06821,0 -1.72731,-0.710245 -1.72731,-1.778452 v -0.07386 h 5.81832 v -0.693199 c 0,-2.875069 -1.75004,-4.454653 -4.22737,-4.454653 -2.63643,0 -4.32965,1.806862 -4.32965,4.511473 0,2.795521 1.67049,4.494426 4.41487,4.494426 z m -1.67617,-5.471723 c 0.0398,-0.869339 0.72729,-1.528446 1.64777,-1.528446 0.91479,0 1.5739,0.636379 1.58526,1.528446 z"
inkscape:connector-curvature="0" />
<path
id="path3228"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 119.89384,19.314899 c 2.4546,0 3.97736,-1.426171 4.05123,-3.585314 h -2.59665 c -0.10228,0.926159 -0.65911,1.431853 -1.42049,1.431853 -0.9773,0 -1.61368,-0.823883 -1.61368,-2.375057 0,-1.53981 0.64206,-2.363693 1.61368,-2.363693 0.79547,0 1.31253,0.539785 1.42049,1.431852 h 2.59665 c -0.0625,-2.147779 -1.63072,-3.54554 -4.05692,-3.54554 -2.74438,0 -4.40351,1.82959 -4.40351,4.505791 0,2.664836 1.64777,4.500108 4.4092,4.500108 z"
inkscape:connector-curvature="0" />
<path
id="path3230"
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16.00038528px;font-family:Inter;-inkscape-font-specification:'Inter, Ultra-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
d="m 125.3826,19.150122 h 2.77848 v -2.619381 l 0.56251,-0.681835 2.0796,3.301216 h 3.2103 l -3.22167,-4.926255 3.09667,-3.801228 h -3.1478 l -2.45461,3.125076 h -0.125 V 7.5134784 h -2.77848 z"
inkscape:connector-curvature="0" />
</g>
<path
d="m 2146.72,133.51812 a 23.030019,11.514995 45 0 1 -24.427,-8.1423 23.030019,11.514995 45 0 1 -8.1423,-24.427 23.030019,11.514995 45 0 1 24.427,8.1423 23.030019,11.514995 45 0 1 8.1423,24.427 z m -16.2137,16.2138 a 23.030019,11.514995 45 0 1 -24.427,-8.1424 23.030019,11.514995 45 0 1 -8.1424,-24.4269 23.030019,11.514995 45 0 1 24.4271,8.1422 23.030019,11.514995 45 0 1 8.1423,24.4271 z"
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:37.79527664;stroke-opacity:1"
id="path1681-6-5-3-7-4-9-2-0-2-7-6"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

View File

@ -133,6 +133,18 @@ function load_spaces(id, is_home, on_success, on_error) {
}, on_error); }, on_error);
} }
function load_importables(user, on_success, on_error) {
load_resource("get", "/users/"+user._id+"/importables", null, on_success, on_error);
}
function import_zip(user, filename, on_success, on_error) {
load_resource("get", "/users/"+user._id+"/import?zip="+filename, null, on_success, on_error);
}
function load_writable_folders(on_success, on_error) {
load_resource("get", "/spaces?writablefolders=true", null, on_success, on_error);
}
function load_history(s, on_success, on_error) { function load_history(s, on_success, on_error) {
load_resource("get", "/spaces/"+ s._id +"/digest", null, on_success, on_error); load_resource("get", "/spaces/"+ s._id +"/digest", null, on_success, on_error);
} }
@ -178,10 +190,12 @@ function delete_space(s, on_success, on_error) {
load_resource("delete", "/spaces/"+s._id, null, on_success, on_error); load_resource("delete", "/spaces/"+s._id, null, on_success, on_error);
} }
function delete_artifact(a, on_success, on_error) { function delete_artifact(a, on_success, on_error) {
load_resource("delete", "/spaces/"+a.space_id+"/artifacts/"+a._id); load_resource("delete", "/spaces/"+a.space_id+"/artifacts/"+a._id);
} }
function duplicate_space(s, to_space_id, on_success, on_error) { function duplicate_space(s, to_space_id, on_success, on_error) {
var path = "/spaces/"+s._id+"/duplicate"; var path = "/spaces/"+s._id+"/duplicate";
if(to_space_id) { if(to_space_id) {
@ -260,8 +274,8 @@ function delete_user(u, password, on_success, on_error) {
load_resource("delete", "/users/"+u._id +"?password="+password,null,on_success,on_error); load_resource("delete", "/users/"+u._id +"?password="+password,null,on_success,on_error);
} }
function create_user(name, email, password, password_confirmation, invite_code, on_success, on_error) { function create_user(name, email, password, password_confirmation, on_success, on_error) {
load_resource("post", "/users", {email:email, nickname:name, password:password, password_confirmation: password_confirmation, invite_code: invite_code}, on_success, on_error); load_resource("post", "/users", {email:email, nickname:name, password:password, password_confirmation: password_confirmation}, on_success, on_error);
} }
function create_session(email, password, on_success, on_error) { function create_session(email, password, on_success, on_error) {

View File

@ -9,12 +9,19 @@ SpacedeckAccount = {
account_tab: 'invoices', account_tab: 'invoices',
password_change_error: null, password_change_error: null,
feedback_text: "", feedback_text: "",
importables: [], // spacedeck.com zip import files
}, },
methods: { methods: {
show_account: function() { show_account: function() {
this.activate_dropdown('account'); this.activate_dropdown('account');
}, },
start_zip_import: function(f) {
if (confirm("Your archive will be imported in the background. This can take a few minutes. You can continue using Spacedeck in the meantime.")) {
import_zip(this.user, f);
}
},
account_save_user_digest: function(val) { account_save_user_digest: function(val) {
this.user.prefs_email_digest = val; this.user.prefs_email_digest = val;
this.save_user(function() { this.save_user(function() {

View File

@ -63,8 +63,8 @@ var SpacedeckSections = {
active_style: { active_style: {
border_radius: 0, border_radius: 0,
stroke: 0, stroke: 0,
font_family: "Inter", font_family: "Avenir W01",
font_size: 36, font_size: 18,
line_height: 1.5, line_height: 1.5,
letter_spacing: 0, letter_spacing: 0,
@ -110,30 +110,18 @@ var SpacedeckSections = {
color_picker_opacity: 255, color_picker_opacity: 255,
swatches: [ swatches: [
{id:1, hex:"#ff00ff"}, {id:0, hex:"#4a2f7e"},
{id:2, hex:"#ffff00"}, {id:1, hex:"#9b59b6"},
{id:3, hex:"#00ffff"}, {id:2, hex:"#3498db"},
{id:5, hex:"#ff0000"}, {id:3, hex:"#2ecc71"},
{id:6, hex:"#00ff00"}, {id:4, hex:"#f1c40f"},
{id:7, hex:"#0000ff"}, {id:5, hex:"#e67e22"},
{id:8, hex:"#000000"}, {id:6, hex:"#d55c4b"},
{id:9, hex:"#222222"}, {id:7, hex:"#6f4021"},
{id:10, hex:"#444444"}, {id:8, hex:"#ffffff"},
{id:11, hex:"#888888"}, {id:9, hex:"#95a5a6"},
{id:12, hex:"#bbbbbb"}, {id:10, hex:"#252525"},
{id:13, hex:"#dddddd"}, {id:11, hex:"rgba(0,0,0,0)"},
{id:14, hex:"#ffffff"},
{id:20, hex:"#4a2f7e"},
{id:21, hex:"#9b59b6"},
{id:22, hex:"#3498db"},
{id:23, hex:"#2ecc71"},
{id:24, hex:"#f1c40f"},
{id:25, hex:"#e67e22"},
{id:26, hex:"#d55c4b"},
{id:27, hex:"#6f4021"},
{id:29, hex:"#95a5a6"},
{id:30, hex:"rgba(0,0,0,0)"},
], ],
swatches_text: [ swatches_text: [
@ -148,8 +136,18 @@ var SpacedeckSections = {
], ],
fonts: [ fonts: [
"Inter", "Arial",
"Courier" "Courier",
"Georgia",
"Verdana",
"Comic Sans MS",
"Montserrat",
"Lato",
"Roboto",
"Crimson Text",
"EB Garamond",
"Vollkorn",
"Avenir W01"
], ],
detected_text_formats: {}, detected_text_formats: {},
@ -182,7 +180,7 @@ var SpacedeckSections = {
toolbar_props_in: false, toolbar_props_in: false,
toolbar_artifacts_x: "-1000px", toolbar_artifacts_x: "-1000px",
toolbar_artifacts_y: "-1000px", toolbar_artifacts_y: "-1000px",
toolbar_artifacts_in: true toolbar_artifacts_in: false
}, },
methods: { methods: {
@ -1059,7 +1057,7 @@ var SpacedeckSections = {
this.toolbar_props_x = pp.x+"px"; this.toolbar_props_x = pp.x+"px";
this.toolbar_props_y = pp.y+"px"; this.toolbar_props_y = pp.y+"px";
//this.hide_toolbar_artifacts(); this.hide_toolbar_artifacts();
} }
this.selection_metrics.x1 = sr.x1; this.selection_metrics.x1 = sr.x1;
@ -1127,12 +1125,9 @@ var SpacedeckSections = {
var er = this.enclosing_rect(this.active_space_artifacts); var er = this.enclosing_rect(this.active_space_artifacts);
if (!er) return; if (!er) return;
// resize space this.active_space.width =Math.max(er.x2+100, window.innerWidth);
this.active_space.width =Math.max((parseInt(er.x2/window.innerWidth)+2)*window.innerWidth, window.innerWidth); this.active_space.height=Math.max(er.y2+100, window.innerHeight);
this.active_space.height=Math.max((parseInt(er.y2/window.innerHeight)+2)*window.innerHeight, window.innerHeight);
console.log("bounds: ",this.active_space.width,this.active_space.height);
if (this._last_bounds_width != this.active_space.width || if (this._last_bounds_width != this.active_space.width ||
this._last_bounds_height != this.active_space.height) { this._last_bounds_height != this.active_space.height) {
this._last_bounds_width = this.active_space.width; this._last_bounds_width = this.active_space.width;
@ -1549,7 +1544,7 @@ var SpacedeckSections = {
add_artifact: function (space, item_type, url, evt) { add_artifact: function (space, item_type, url, evt) {
this.active_tool = "pointer"; this.active_tool = "pointer";
this.mouse_state = "idle"; this.mouse_state = "idle";
//this.hide_toolbar_artifacts(); this.hide_toolbar_artifacts();
if (!url && (item_type == 'image' || item_type == 'video' || item_type == 'embed')) { if (!url && (item_type == 'image' || item_type == 'video' || item_type == 'embed')) {
url = prompt("URL?"); url = prompt("URL?");
@ -1729,7 +1724,7 @@ var SpacedeckSections = {
var a = { var a = {
space_id: this.active_space._id, space_id: this.active_space._id,
mime: "x-spacedeck/shape", mime: "x-spacedeck/shape",
description: "", description: "Text",
x: point.x, x: point.x,
y: point.y, y: point.y,
z: point.z, z: point.z,
@ -1741,7 +1736,7 @@ var SpacedeckSections = {
fill_color: "#000000", fill_color: "#000000",
shape: shape_type, shape: shape_type,
valign: "middle", valign: "middle",
align: "center", align: "center"
}; };
if (this.guest_nickname) { if (this.guest_nickname) {
@ -1793,7 +1788,9 @@ var SpacedeckSections = {
if (this.active_space_role=="viewer") { if (this.active_space_role=="viewer") {
return false; return false;
} }
this.hide_toolbar_artifacts();
// 1. create placeholder artifact // 1. create placeholder artifact
var w=300,h=150; var w=300,h=150;
var fill="transparent"; var fill="transparent";
@ -2296,6 +2293,11 @@ var SpacedeckSections = {
if (!pastedText) return; if (!pastedText) return;
if (!pastedText.match(/<[a-zA-Z]+>/g)) {
// crappy heuristic if this is actually HTML
pastedText = pastedText.replace(/\n/g,"<br>");
}
this.insert_embedded_artifact(pastedText); this.insert_embedded_artifact(pastedText);
}, },
@ -2342,6 +2344,32 @@ var SpacedeckSections = {
this.create_artifact_via_embed_url(text); this.create_artifact_via_embed_url(text);
return; return;
} }
var new_item = {
mime: "text/html",
description: text.replace("\n", "<br />"),
title: "",
space_id: space._id
};
var w = 400;
var h = 300;
var point = this.find_place_for_item(w,h);
new_item.x = point.x;
new_item.y = point.y;
new_item.w = w;
new_item.h = h;
new_item.z = point.z;
if (this.guest_nickname) {
new_item.editor_name = this.guest_nickname;
}
save_artifact(new_item, function(saved_item) {
this.update_board_artifact_viewmodel(saved_item);
this.active_space_artifacts.push(saved_item);
}.bind(this));
}, },
create_artifact_via_embed_url: function(url) { create_artifact_via_embed_url: function(url) {
@ -2500,9 +2528,18 @@ var SpacedeckSections = {
this.opened_dialog = "none"; this.opened_dialog = "none";
if (files && files.length) { if (files && files.length) {
console.log("file: ",files[0]);
for (var i=0; i<files.length; i++) { for (var i=0; i<files.length; i++) {
var file = files[i]; var file = files[i];
this.create_artifact_via_upload(null, file, true); if (file.type === "application/pdf") {
var point = {x: 100, y: 100}; //fixme, center upload?
this.dropped_point = point;
this.pending_pdf_file = file;
this.activate_modal('pdfoptions');
} else {
this.create_artifact_via_upload(null, file, true);
}
} }
} }
}, },
@ -2541,11 +2578,12 @@ var SpacedeckSections = {
}, },
hide_toolbar_props: function() { hide_toolbar_props: function() {
// FIXME test this.toolbar_props_in = false;
//this.toolbar_props_in = false;
}, },
show_toolbar_artifacts: function(x,y) { show_toolbar_artifacts: function(x,y) {
this.toolbar_artifacts_x = (x-175)+"px";
this.toolbar_artifacts_y = y+"px";
this.toolbar_artifacts_in = true; this.toolbar_artifacts_in = true;
}, },
@ -2555,19 +2593,29 @@ var SpacedeckSections = {
start_adding_artifact: function(evt) { start_adding_artifact: function(evt) {
evt = fixup_touches(evt); evt = fixup_touches(evt);
// toggle
if (this.toolbar_artifacts_in) {
this.hide_toolbar_artifacts();
return;
}
this.show_toolbar_artifacts(evt.pageX,evt.pageY);
}, },
start_drawing_scribble: function(evt) { start_drawing_scribble: function(evt) {
this.hide_toolbar_artifacts();
this.active_tool = "scribble"; this.active_tool = "scribble";
this.opened_dialog = "none"; this.opened_dialog = "none";
}, },
start_drawing_arrow: function(evt) { start_drawing_arrow: function(evt) {
this.hide_toolbar_artifacts();
this.active_tool = "arrow"; this.active_tool = "arrow";
this.opened_dialog = "none"; this.opened_dialog = "none";
}, },
start_drawing_line: function(evt) { start_drawing_line: function(evt) {
this.hide_toolbar_artifacts();
this.active_tool = "line"; this.active_tool = "line";
this.opened_dialog = "none"; this.opened_dialog = "none";
}, },
@ -2846,6 +2894,32 @@ var SpacedeckSections = {
}.bind(this),500); }.bind(this),500);
}, },
approve_pdf_upload: function(evt,approve_pdf_upload, mode){
this.close_modal();
if(mode == "classic"){
this.create_artifact_via_upload(evt, this.pending_pdf_file, false);
}
if(mode == "grid") {
this.global_spinner = true;
save_pdf_file(this.active_space, this.dropped_point, this.pending_pdf_file, approve_pdf_upload, function(createdArtifacts){
this.global_spinner = false;
_.each(createdArtifacts, function(new_artifact){
this.update_board_artifact_viewmodel(new_artifact);
this.active_space_artifacts.push(new_artifact)
}.bind(this));
}.bind(this), function(xhr) {
this.global_spinner = false;
alert("Error PDF ("+xhr.status+")");
}.bind(this));
}
},
handle_data_drop: function(evt) { handle_data_drop: function(evt) {
if (this.active_space_role=="viewer") { if (this.active_space_role=="viewer") {
return false; return false;
@ -2858,8 +2932,17 @@ var SpacedeckSections = {
if (files && files.length) { if (files && files.length) {
for (var i=0; i<files.length; i++) { for (var i=0; i<files.length; i++) {
var file = files[i]; var file = files[i];
this.create_artifact_via_upload(evt, file, (files.length>1)); if (file.type === "application/pdf") {
var point = this.cursor_point_to_space(evt);
this.dropped_point = point;
this.pending_pdf_file = file;
this.activate_modal('pdfoptions');
} else {
this.create_artifact_via_upload(evt, file, (files.length>1));
}
} }
} else { } else {
var json = evt.dataTransfer.getData('application/json'); var json = evt.dataTransfer.getData('application/json');

View File

@ -18,6 +18,8 @@ var SpacedeckSpaces = {
active_space_path: [], active_space_path: [],
access_settings_space: null, access_settings_space: null,
access_settings_memberships: [], access_settings_memberships: [],
duplicate_folders: [],
duplicate_folder_id: "",
pending_pdf_files: [], pending_pdf_files: [],
meta_visible: false, meta_visible: false,
@ -108,6 +110,27 @@ var SpacedeckSpaces = {
space_auth = get_query_param("spaceAuth"); space_auth = get_query_param("spaceAuth");
var userReady = function() { var userReady = function() {
if (get_query_param("embedded")) {
this.embedded = true;
this.guest_signup_enabled = true;
if (get_query_param("publish_cta")) {
this.publish_cta = get_query_param("publish_cta");
}
if (get_query_param("nosocial")) {
this.social_bar = false;
}
}
if (get_query_param("confirm") && this.logged_in) {
var token = get_query_param("confirm");
confirm_user(this.user, token, function() {
this.redirect_to("/spaces/"+space_id+"?show_access=1");
}.bind(this), function() {
alert("An error occured confirming your email with the given token.");
});
return;
}
this.close_dropdown(); this.close_dropdown();
this.active_space_loaded = false; this.active_space_loaded = false;
@ -135,7 +158,9 @@ var SpacedeckSpaces = {
load_space(space_id, function(space, role) { load_space(space_id, function(space, role) {
document.title = space.name; document.title = space.name;
this.active_space_role = role || "viewer"; // via req header from backend this.active_space_role = role || "viewer"; //via req header from backend
this.space_embed_html = "<iframe width=\"1024\" height=\"768\" seamless src=\""+ENV.webEndpoint+"/spaces/"+space._id+"?embedded=1\"></iframe>";
if (!is_home) { if (!is_home) {
load_members(space, function(members) { load_members(space, function(members) {
@ -248,9 +273,9 @@ var SpacedeckSpaces = {
this.discover_zones(); this.discover_zones();
window.setTimeout(function() { //window.setTimeout(function() {
this.zoom_to_fit(); // this.zoom_to_fit();
}.bind(this),10); //}.bind(this),10);
if (on_success) { if (on_success) {
on_success(); on_success();
@ -276,6 +301,15 @@ var SpacedeckSpaces = {
// FIXME // FIXME
this.active_join_link = ""; this.active_join_link = "";
this.join_link_role = "viewer"; this.join_link_role = "viewer";
// FIXME
if (this.active_space_role == "admin") {
this.space_info_section="access";
} else if (this.active_space_role == "editor") {
//this.space_info_section="versions";
} else {
this.space_info_section="info";
}
} }
}.bind(this), function(xhr) { }.bind(this), function(xhr) {
@ -304,7 +338,7 @@ var SpacedeckSpaces = {
userReady(); userReady();
} }
if (!this.user && space_auth) { if (space_auth) {
if (this.guest_nickname) { if (this.guest_nickname) {
userReady(); userReady();
} else { } else {
@ -639,6 +673,47 @@ var SpacedeckSpaces = {
location.href = "/api/spaces/" + space._id + "/list"; location.href = "/api/spaces/" + space._id + "/list";
}, },
duplicate_space_into_folder: function() {
load_writable_folders( function(folders){
this.duplicate_folders = _.sortBy(folders, function (folder) { return folder.name; });
}.bind(this), function(xhr) {
console.error(xhr);
});
},
duplicate_folder_confirm: function() {
var folderId = this.duplicate_folder_id;
var idx = _.findIndex(this.duplicate_folders, function(s) { return s._id == folderId;});
if (idx<0) idx = 0;
var folder = this.duplicate_folders[idx];
console.log("df f",folder);
if (!folder) return;
duplicate_space(this.active_space, folder._id, function(new_space) {
this.duplicate_folders = [];
this.duplicate_folder = null;
smoke.quiz(__("duplicate_success", this.active_space.name, folder.name), function(e, test){
if (e == __("goto_space", new_space.name)){
this.redirect_to("/spaces/" + new_space._id);
}else if (e == __("goto_folder", folder.name)){
this.redirect_to("/folders/" + folder._id);
}
}.bind(this), {
button_1: __("goto_space", new_space.name),
button_2: __("goto_folder", folder.name),
button_cancel:__("stay_here")
});
}.bind(this), function(xhr){
console.error(xhr);
smoke.prompt("error: " + xhr.statusText);
}.bind(this));
},
toggle_follow_mode: function() { toggle_follow_mode: function() {
this.deselect(); this.deselect();
this.follow_mode = !this.follow_mode; this.follow_mode = !this.follow_mode;
@ -744,12 +819,9 @@ var SpacedeckSpaces = {
this.invite_message = ""; this.invite_message = "";
} }
}.bind(this), function(xhr){ }.bind(this), function(xhr){
try {
var res = JSON.parse(xhr.response); text = JSON.stringify(xhr.responseText);
alert("Error: "+res.error); smoke.alert("Error: "+text);
} catch (e) {
console.error(e, xhr);
}
}.bind(this)); }.bind(this));
}.bind(this)); }.bind(this));
}, },
@ -757,13 +829,9 @@ var SpacedeckSpaces = {
update_member: function(space, m, role) { update_member: function(space, m, role) {
m.role = role; m.role = role;
save_membership(space, m, function() { save_membership(space, m, function() {
console.log("saved")
}.bind(this), function(xhr) { }.bind(this), function(xhr) {
try { console.error(xhr);
var res = JSON.parse(xhr.response);
alert("Error: "+res.error);
} catch (e) {
console.error(e, xhr);
}
}.bind(this)); }.bind(this));
}, },
@ -772,12 +840,7 @@ var SpacedeckSpaces = {
delete_membership(space, m, function() { delete_membership(space, m, function() {
this.access_settings_memberships.splice(this.access_settings_memberships.indexOf(m), 1); this.access_settings_memberships.splice(this.access_settings_memberships.indexOf(m), 1);
}.bind(this), function(xhr) { }.bind(this), function(xhr) {
try { console.error(xhr);
var res = JSON.parse(xhr.response);
alert("Error: "+res.error);
} catch (e) {
console.error(e, xhr);
}
}.bind(this)); }.bind(this));
}, },
@ -813,6 +876,10 @@ var SpacedeckSpaces = {
}.bind(this)); }.bind(this));
}, },
emojified_comment: function(comment) {
return twemoji.parse(comment);
},
set_folder_sorting: function(key,reverse) { set_folder_sorting: function(key,reverse) {
this.folder_sorting = key; this.folder_sorting = key;
this.folder_reverse = reverse?-1:1; this.folder_reverse = reverse?-1:1;

View File

@ -11,7 +11,6 @@ SpacedeckUsers = {
login_email: "", login_email: "",
login_password: "", login_password: "",
signup_password: "", signup_password: "",
signup_invite_code: "",
signup_password_confirmation: "", signup_password_confirmation: "",
account_remove_error: null, account_remove_error: null,
loading_user: false, loading_user: false,
@ -31,6 +30,12 @@ SpacedeckUsers = {
if (on_success) { if (on_success) {
on_success(user); on_success(user);
} }
// see spacedeck_account.js
load_importables(this.user, function(files) {
this.importables = files;
}.bind(this));
}.bind(this), function() { }.bind(this), function() {
// error // error
this.loading_user = false; this.loading_user = false;
@ -117,7 +122,7 @@ SpacedeckUsers = {
signup_guest: function(on_success) { signup_guest: function(on_success) {
}, },
signup_submit: function($event, name, email, password, password_confirmation, invite_code, on_success) { signup_submit: function($event, name, email, password, password_confirmation, on_success) {
this.creating_user = true; this.creating_user = true;
this.signup_error = null; this.signup_error = null;
@ -131,7 +136,7 @@ SpacedeckUsers = {
$event.stopPropagation(); $event.stopPropagation();
} }
create_user(name, email, password, password_confirmation, invite_code, function(session) { create_user(name, email, password, password_confirmation, function(session) {
this.creating_user = false; this.creating_user = false;
this.login_submit(email, password, null, on_success); this.login_submit(email, password, null, on_success);
}.bind(this), function(req) { }.bind(this), function(req) {
@ -147,8 +152,8 @@ SpacedeckUsers = {
}.bind(this)); }.bind(this));
}, },
signup_submit_modal: function($event, name, email, password, password_confirmation, invite_code) { signup_submit_modal: function($event, name, email, password, password_confirmation) {
this.signup_submit($event, name, email, password, password_confirmation, invite_code, function() { this.signup_submit($event, name, email, password, password_confirmation, function() {
alert("Success."); alert("Success.");
location.reload(); location.reload();
}); });
@ -196,29 +201,27 @@ SpacedeckUsers = {
this.password_reset_confirm_error = null; this.password_reset_confirm_error = null;
this.password_reset_send = false; this.password_reset_send = false;
if (password != password_confirmation) { if(password != password_confirmation) {
this.password_reset_confirm_error = "Passwords do not match."; this.password_reset_confirm_error = "Passwords do not match.";
return; return;
} }
if (password.length < 5) { if(password.length < 5) {
this.password_reset_confirm_error = "Password too short (must have at least 5 characters)."; this.password_reset_confirm_error = "Password too short (must have at least 5 characters).";
return; return;
} }
confirm_password_reset(password, this.reset_token, function(parsed,req) { confirm_password_reset(password, this.reset_token, function(parsed,req) {
if (req.status==201) { if(req.status==201){
alert("New password set successfully.");
this.active_view = "login"; this.active_view = "login";
} else {
alert("An unknown error occured.");
} }
}.bind(this), function(req) { }.bind(this), function(req) {
if (req.status==404) { if (req.status==404) {
alert("Error: Unknown user."); var msg = "user not found";
} else { } else {
alert("Error: "+req.statusText); var msg = "error: " + req.statusText;
} }
this.password_reset_confirm_error = msg;
}.bind(this)); }.bind(this));
}, },

View File

@ -80,16 +80,10 @@ function setup_whiteboard_directives() {
evt.stopPropagation(); evt.stopPropagation();
} }
if ($scope.active_tool == "zoom") return;
if (evt.which == 2) {
// middle mouse button
this.handle_mouse_down_space(evt);
return;
}
var a = $scope.find_artifact_by_id(evt.currentTarget.id.replace("artifact-","")); var a = $scope.find_artifact_by_id(evt.currentTarget.id.replace("artifact-",""));
if ($scope.active_tool == "zoom") return;
if ($scope.active_tool == "eyedrop") { if ($scope.active_tool == "eyedrop") {
var arts = $scope.selected_artifacts(); var arts = $scope.selected_artifacts();
if (!$scope.is_selected(a) && arts.length > 0) { if (!$scope.is_selected(a) && arts.length > 0) {
@ -202,10 +196,8 @@ function setup_whiteboard_directives() {
}, },
handle_mouse_down_space: function(evt) { handle_mouse_down_space: function(evt) {
if (evt.which != 2) { if (evt.target != evt.currentTarget && !_.include(["wrapper"],evt.target.className)) return;
if (evt.target != evt.currentTarget && !_.include(["wrapper"],evt.target.className)) return;
}
var $scope = this.vm.$root; var $scope = this.vm.$root;
$scope.opened_dialog="none"; $scope.opened_dialog="none";
@ -222,7 +214,7 @@ function setup_whiteboard_directives() {
this.deselect(); this.deselect();
this.mouse_state = "transform"; this.mouse_state = "transform";
$scope.mouse_state = this.mouse_state; $scope.mouse_state = this.mouse_state;
this.start_drawing_note(evt); this.start_adding_note(evt);
return; return;
} else if ($scope.active_tool=="arrow") { } else if ($scope.active_tool=="arrow") {
@ -500,7 +492,6 @@ function setup_whiteboard_directives() {
if (!xdists[0] || xdists[0][0]>TOL) { if (!xdists[0] || xdists[0][0]>TOL) {
results.snapx = [0,x]; // distance, coordinate results.snapx = [0,x]; // distance, coordinate
} else { } else {
// FIXME snap rulers are broken
//$scope.snap_ruler_x = xdists[0][1]; //$scope.snap_ruler_x = xdists[0][1];
} }
if (!ydists[0] || ydists[0][0]>TOL) { if (!ydists[0] || ydists[0][0]>TOL) {
@ -525,41 +516,6 @@ function setup_whiteboard_directives() {
return point; return point;
}, },
start_drawing_note: function(evt) {
evt.preventDefault();
evt.stopPropagation();
var $scope = this.vm.$root;
var point = this.cursor_point_to_space(evt);
this.offset_point_in_wrapper(point);
var z = $scope.highest_z()+1;
var a = {
space_id: $scope.active_space._id,
mime: "text/html",
description: "<p>Text</p>",
x: point.x,
y: point.y,
z: z,
w: 64,
h: 64,
align: "center",
valign: "middle",
stroke_color: "#000000",
fill_color: "rgb(241, 196, 15)",
stroke: 0
};
$scope.save_artifact(a, function(saved_a) {
$scope.update_board_artifact_viewmodel(saved_a);
$scope.active_space_artifacts.push(saved_a);
$scope.select(evt,a);
$scope.transform_ox = 0;
$scope.transform_oy = 0;
$scope.begin_transaction();
}.bind(this));
},
start_drawing_scribble: function(evt) { start_drawing_scribble: function(evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
@ -735,7 +691,7 @@ function setup_whiteboard_directives() {
this.mouse_state = "idle"; this.mouse_state = "idle";
$scope.mouse_state = this.mouse_state; $scope.mouse_state = this.mouse_state;
this.lasso = null; this.lasso = null;
//$scope.active_tool = "pointer"; disabled to keep the same tool (eg. "Scribble") after drawing a single line. $scope.active_tool = "pointer";
$scope.end_transaction(); $scope.end_transaction();
$scope.show_toolbar_props(); $scope.show_toolbar_props();
@ -895,7 +851,7 @@ function setup_whiteboard_directives() {
var scale_x = lead_x ? (moved_x)/lead_x : 1; var scale_x = lead_x ? (moved_x)/lead_x : 1;
var scale_y = lead_y ? (moved_y)/lead_y : 1; var scale_y = lead_y ? (moved_y)/lead_y : 1;
if ($scope.transform_lock) scale_y = scale_x; if (!$scope.transform_lock) scale_y = scale_x;
$scope.update_selected_artifacts(function(a) { $scope.update_selected_artifacts(function(a) {
var old_a = $scope.find_artifact_before_transaction(a); var old_a = $scope.find_artifact_before_transaction(a);

File diff suppressed because it is too large Load Diff

View File

@ -138,6 +138,7 @@ 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) {

View File

@ -51,7 +51,8 @@ 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", function(local_path) { phantom.takeScreenshot(req.space, "png",
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) {
@ -78,14 +79,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.unlinkSync(local_path); fs.unlink(local_path);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}); });
try { try {
fs.unlinkSync(localResizedFilePath); fs.unlink(localResizedFilePath);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@ -94,7 +95,7 @@ router.get('/png', function(req, res, next) {
}, },
function() { function() {
// on_error // on_error
console.error("[space screenshot] could not create screenshot for space " + req.space_id); console.error("phantom could not create screenshot for space " + req.space_id);
res.status(404).send("Not found"); res.status(404).send("Not found");
}); });
} else { } else {

View File

@ -45,12 +45,10 @@ 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);
} }
@ -86,13 +84,13 @@ router.post('/', function(req, res, next) {
} else { } else {
res.status(400).json({ res.status(400).json({
"error": "This email is already included in the Space memberships." "error": "user already in space"
}); });
} }
} else { } else {
res.status(403).json({ res.status(403).json({
"error": "Only administrators can do that." "error": "not_permitted"
}); });
} }
}); });
@ -104,18 +102,11 @@ 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) {
// is the user trying to change their own role? var attrs = req.body;
if (mem.user_id == req.user._id) { mem.role = attrs.role;
res.status(400).json({ mem.save(function() {
"error": "Cannot change your own role." res.status(201).json(mem);
}); });
} else {
var attrs = req.body;
mem.role = attrs.role;
mem.save(function() {
res.status(201).json(mem);
});
}
} }
}); });
} else { } else {
@ -127,25 +118,13 @@ 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 && req.spaceRole == 'admin') { if (req.user) {
db.Membership.count({ where: { db.Membership.findOne({ where: {
space_id: req.space._id, _id: req.params.membership_id
role: "admin" }}).then(function(mem) {
}}).then(function(adminCount) { mem.destroy().then(function() {
db.Membership.findOne({ where: { res.sendStatus(204);
_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);

View File

@ -48,12 +48,74 @@ router.get('/', function(req, res, next) {
error: "auth required" error: "auth required"
}); });
} else { } else {
if (req.query.search) { if (req.query.writablefolders) {
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;
@ -81,8 +143,7 @@ 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 db.Space
.findOne({where: { .findOne({where: {
_id: req.query.parent_space_id _id: req.query.parent_space_id
@ -115,17 +176,14 @@ router.get('/', function(req, res, next) {
}); });
} 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) {
@ -170,18 +228,14 @@ router.post('/', function(req, res, next) {
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 = slug(attrs.name);
attrs.access_mode = "private";
db.Space.create(attrs).then(createdSpace => { db.Space.create(attrs).then(createdSpace => {
res.status(201).json(createdSpace); //if (err) res.sendStatus(400);
// 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(() => {
@ -260,17 +314,8 @@ 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
@ -317,6 +362,43 @@ 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;
@ -336,4 +418,136 @@ 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;

View File

@ -51,18 +51,12 @@ 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;
@ -89,31 +83,28 @@ router.post('/', function(req, res) {
res.sendStatus(400); res.sendStatus(400);
}) })
.then(u => { .then(u => {
var homeFolder = { var homeSpace = {
_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(homeFolder) db.Space.create(homeSpace)
.error(err => { .error(err => {
res.sendStatus(400); res.sendStatus(400);
}) })
.then(homeFolder => { .then(homeSpace => {
u.home_folder_id = homeFolder._id; u.home_folder_id = homeSpace._id;
u.save() u.save()
.then(() => { .then(() => {
// home folder created, res.status(201).json({});
// auto accept pending invites
db.Membership.update({ mailer.sendMail(u.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), {
"state": "active" action: {
}, { link: config.endpoint + "/confirm/" + u.confirmation_token,
where: { name: req.i18n.__("confirm_action")
"email_invited": u.email,
"state": "pending"
} }
}); });
res.status(201).json({});
}) })
.error(err => { .error(err => {
res.status(400).json(err); res.status(400).json(err);
@ -128,6 +119,7 @@ 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"});
@ -176,35 +168,36 @@ router.post('/:id/password', function(req, res, next) {
}); });
}); });
} else { } else {
res.status(403).json({"error": "Please enter the correct current password."}); res.status(403).json({"error": "old password wrong"});
} }
} else { } else {
res.status(403).json({"error": "Access denied."}); res.status(403).json({"error": "wrong user"});
} }
} else { } else {
res.status(400).json({"error": "Please choose a new password with at least 6 characters."}); res.status(400).json({"error": "password_to_short"});
} }
}); });
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 (bcrypt.compareSync(req.query.password, user.password_hash)) { if (user.account_type == 'email') {
if (bcrypt.compareSync(req.query.password, user.password_hash)) {
// TODO: this doesn't currently work. user.remove((err) => {
// all objects (indirectly) belonging to the user have if(err)res.status(400).json(err);
// to be walked and deleted first. else res.sendStatus(204);
});
user.destroy().then(err => { } else {
if(err)res.status(400).json(err); res.bad_request("password_incorrect");
}
} 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) => {
@ -260,6 +253,13 @@ 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) => {
@ -283,16 +283,21 @@ router.post('/password_reset_requests', (req, res, next) => {
router.post('/password_reset_requests/:confirm_token/confirm', function(req, res, next) { router.post('/password_reset_requests/:confirm_token/confirm', function(req, res, next) {
var password = req.body.password; var password = req.body.password;
db.User User
.findOne({where: {"password_reset_token": req.params.confirm_token}}) .findOne({where: {"password_reset_token": req.params.confirm_token}})
.then((user) => { .then((user) => {
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().then(function(updatedUser) { user.save(function(err, updatedUser){
res.sendStatus(201); if (err) {
res.sendStatus(400);
} else {
res.sendStatus(201);
}
}); });
}); });
}); });
@ -310,4 +315,19 @@ 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;

View File

@ -54,6 +54,10 @@ router.get('/password-confirm/:token', (req, res) => {
res.render('spacedeck', { title: 'Signup' }); res.render('spacedeck', { title: 'Signup' });
}); });
router.get('/team', (req, res) => {
res.render('spacedeck');
});
router.get('/de/*', (req, res) => { router.get('/de/*', (req, res) => {
res.redirect("/t/de"); res.redirect("/t/de");
}); });
@ -78,6 +82,10 @@ router.get('/en', (req, res) => {
res.redirect("/t/end"); res.redirect("/t/end");
}); });
router.get('/it', (req, res) => {
res.redirect("/t/en");
});
router.get('/account', (req, res) => { router.get('/account', (req, res) => {
res.render('spacedeck'); res.render('spacedeck');
}); });
@ -124,15 +132,15 @@ router.get('/s/:token', (req, res) => {
db.Space.findOne({where: {"edit_hash": token}}).then(function (space) { db.Space.findOne({where: {"edit_hash": token}}).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=" + token);
} 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', { title: 'Page Not Found.' });
} else { } else {
res.status(404).json({}); res.status(404).json({});
} }
} }
}); });

View File

@ -26,9 +26,6 @@ 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'));
@ -75,7 +72,7 @@ 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())

View File

@ -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,10 +469,11 @@
color: black; color: black;
//@include user-select(none); //@include user-select(none);
white-space: normal; white-space: normal;
font-size: 36px; font-size: 18px;
&.artifact-zone { &.artifact-zone {
background-color: rgba(0,0,0,0.05); border: 1px solid rgba(46,204,113,1);
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; }
@ -552,10 +553,6 @@ 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;

View File

@ -7,6 +7,12 @@
.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);
} }
} }
@ -58,7 +64,7 @@
backface-visibility: hidden; backface-visibility: hidden;
cursor: pointer; cursor: pointer;
background-color: $light; background-color: $light;
color: $black; color: $medium;;
@include user-select(none); @include user-select(none);
&:last-child {border: none;} &:last-child {border: none;}
@ -76,9 +82,12 @@
&.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;
} }
@ -87,10 +96,21 @@
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 {
@ -103,7 +123,7 @@
&.btn-stroke { &.btn-stroke {
box-shadow: inset 0 0 0 1px $dark; box-shadow: inset 0 0 0 1px $dark;
color: $black; color: $dark !important;
background-color: transparent; background-color: transparent;
&:active { &:active {
box-shadow: inset 0 0 0 1px white; box-shadow: inset 0 0 0 1px white;
@ -112,8 +132,9 @@
} }
&.btn-stroke-darken { &.btn-stroke-darken {
border: 1px solid $black; //box-shadow: inset 0 0 0 1px rgba(0,0,0,0.1);
color: $black; border: 1px solid rgba(0,0,0,0.1);
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;
@ -242,18 +263,9 @@
&.btn-transparent { &.btn-transparent {
background-color: transparent; background-color: transparent;
color: $dark; color: $medium;
&.active { &.active {color: $darker !important; }
//color: $black !important; &.open {color: white !important; }
color: $white;
background-color: $black;
}
&.open {
//color: $black !important;
color: $white;
background-color: $black;
border-radius: 0;
}
} }
&.btn-transparent-medium { &.btn-transparent-medium {
@ -301,7 +313,7 @@
&.btn-dark { &.btn-dark {
background-color: $dark ; background-color: $dark ;
color: $white; color: $medium;
} }
&.btn-medium { &.btn-medium {
@ -469,6 +481,7 @@
&.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; }
@ -495,6 +508,30 @@
} }
} }
&.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;
@ -530,6 +567,7 @@
.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;
@ -542,7 +580,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
padding: 0 0px; padding: 0 0px;
font-weight: 300; font-weight: bold;
} }
&.hover { &.hover {
@ -676,6 +714,7 @@
} }
> * { > * {
border-radius: 0 !important;
background-clip: padding-box; background-clip: padding-box;
width: 100%; width: 100%;
float: left; float: left;
@ -736,7 +775,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;
@ -748,7 +787,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);
@ -940,7 +979,31 @@
} }
} }
// !btn-group .btn-group.bottom-left > .btn {
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;
@ -951,16 +1014,13 @@
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: $white; color: $lighter;
.btn { .btn {
color: $white; color: $lighter;
} }
} }
@ -1099,4 +1159,4 @@
margin: 4px; margin: 4px;
z-index: 100; z-index: 100;
border-radius: 50px; border-radius: 50px;
} }

View File

@ -96,37 +96,41 @@
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;
position: absolute; @include backface-visibility(hidden);
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; white-space: normal;
z-index: 1000;
position: absolute;
// white-space: normal;
opacity: 0; opacity: 0;
@include transition(all 0.125s ease-in-out); @include user-select(none);
@include transition( all 0.125s ease-in-out);
pointer-events: none; pointer-events: none;
background-color: $light; background-color: $light;
color: $dark; color: $medium;
&.dark { &.dark {background-color: $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;
@ -146,13 +150,15 @@
&:hover span {color: $dark; } &:hover span {color: $dark; }
&.open span { &.open span {
background-color: white; background-color: $light;
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 {
@ -194,6 +200,7 @@
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);
@ -221,13 +228,4 @@
h4 .icon { h4 .icon {
height: 38px; height: 38px;
} }
}
// account dialog
&.dialog-freestanding {
margin: auto;
position: relative;
top: 150px;
border: none;
width: 800px;
}
}

View File

@ -43,6 +43,9 @@ $predelay: 0;
&.hover:hover, &.hover:hover,
&.open { &.open {
// &:before {opacity: 0.125; }
// pointer-events: auto;
background-color: $dark;
background-color: $light; background-color: $light;
> * { > * {
@ -108,8 +111,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 ;
} }
} }
} }
@ -118,10 +121,6 @@ $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;
@ -144,7 +143,8 @@ $predelay: 0;
&.light > .dropdown-menu, &.light > .dropdown-menu,
&.light > .dialog { &.light > .dialog {
background: white; background: $light;
color: $medium;
} }
> .dropdown-menu { > .dropdown-menu {
@ -189,6 +189,8 @@ $predelay: 0;
} }
} }
&.hover:hover > .dialog, &.hover:hover > .dialog,
&.hover:hover > .dropdown-menu, &.hover:hover > .dropdown-menu,
@ -204,7 +206,9 @@ $predelay: 0;
&.open { &.open {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
//transform: translate3d(-50%, -50%, 100px) scale(1); -webkit-transform: translate3d(-50%, -50%, 100px) scale(1);
-ms-transform: translate3d(-50%, -50%, 100px) scale(1);
transform: translate3d(-50%, -50%, 100px) scale(1);
} }
} }
@ -213,8 +217,10 @@ $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);
//transform: translate3d(-50%, -50%, 100px) scale(0.93,0.8); -webkit-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);
} }
} }
@ -224,8 +230,10 @@ $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);
//transform: translate3d(-33%, 0%, 100px) scale(0.93,0.8); -webkit-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);
} }
} }
@ -235,8 +243,10 @@ $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);
//transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8); -webkit-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);
} }
} }
@ -247,37 +257,33 @@ $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);
//transform: translate3d(-50%, 0%, 100px) scale(0.93,0.8); -webkit-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;
right: 70px; margin-top: 16px;
margin-top: -60px; @include transform-origin(top right);
-webkit-transform: translate3d(0%, 0%, 100px) scale(0.93,0.8);
//@include transform-origin(top right); -ms-transform: translate3d(0%, 0%, 100px) scale(0.93,0.8);
//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 {
//transform: translate3d(0%, 0%, 100px) scale(1); -webkit-transform: translate3d(0%, 0%, 100px) scale(1);
-ms-transform: translate3d(0%, 0%, 100px) scale(1);
transform: translate3d(0%, 0%, 100px) scale(1);
} }
} }
@ -306,7 +312,9 @@ $predelay: 0;
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
//transform: translate3d(-50%, 0%, 100px) scale(1); -webkit-transform: translate3d(-50%, 0%, 100px) scale(1);
-ms-transform: translate3d(-50%, 0%, 100px) scale(1);
transform: translate3d(-50%, 0%, 100px) scale(1);
} }
} }
} }
@ -316,7 +324,9 @@ $predelay: 0;
&.open { &.open {
> .dialog, > .dialog,
> .dropdown-menu { > .dropdown-menu {
//transform: translate3d(-33%, 0%, 100px) scale(1) !important; -webkit-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;
} }
} }
} }
@ -324,7 +334,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;}
@ -338,9 +348,8 @@ $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: "";
@ -353,24 +362,26 @@ $predelay: 0;
margin-left: -8px; margin-left: -8px;
pointer-events: none !important; pointer-events: none !important;
left: 50%; left: 50%;
//transform: scale(0,0); -webkit-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;
}*/ }
} }

View File

@ -254,6 +254,7 @@
// 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;
@ -396,10 +397,7 @@
&:active { opacity: 0.95 !important; } &:active { opacity: 0.95 !important; }
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15); box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.025), 0 2px 7px rgba(0, 0, 0, 0.025);
border: 1px solid black;
// ???
@include opacity(1); @include opacity(1);
color: $medium; color: $medium;
// color: white; // color: white;
@ -478,6 +476,7 @@
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;
@ -502,6 +501,30 @@
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 {

View File

@ -28,6 +28,7 @@
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;
@ -138,4 +139,4 @@
display: inline-block !important; display: inline-block !important;
width: auto !important; width: auto !important;
padding-right: 15px !important; padding-right: 15px !important;
} }

View File

@ -2,14 +2,24 @@
@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%;

View File

@ -23,6 +23,7 @@ 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;
@ -112,26 +113,43 @@ 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();

View File

@ -69,27 +69,26 @@
} }
.handles { .handles {
//border: 1px solid rgba(255,255,255,0.5); // background-color: rgba(40,140,215,0.45);
border: 1px solid rgba(255,255,255,0.5);
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
bottom: -1; bottom: 0;
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: 4px dotted #000000; border: 1px dotted rgba(40,140,215,1);
content: ""; content: "";
display: block; display: block;
position: absolute; position: absolute;
height: auto; height: auto;
width: auto; width: auto;
top: 0px; top: -1px;
left: 0px; left: -1px;
right: 0px; right: -1px;
bottom: -1px; bottom: -1px;
} }
} }
@ -98,7 +97,7 @@
border: 8px solid rgba(255,255,255,0.5); border: 8px solid rgba(255,255,255,0.5);
&:after{ &:after{
border: 8px dotted #000000; border: 8px dotted rgba(40,140,215,1);
top: -4px; top: -4px;
left: -4px; left: -4px;
right: -4px; right: -4px;
@ -333,15 +332,16 @@
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: black; background-color: rgba(255,255,255,0.5);
cursor: move; cursor: move;
} }
} }
@ -428,8 +428,15 @@
border-style: solid; border-style: solid;
border-width: 10px; border-width: 10px;
border-color: transparent; border-color: transparent;
background-clip: padding-box; -webkit-background-clip: padding-box;
transition: all .05s ease-in-out; -moz-background-clip: padding-box;
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 {

View File

@ -5,6 +5,7 @@
.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;
@ -26,21 +27,21 @@
.home { .home {
margin-top: -20px; margin-top: -20px;
margin-left: -20px; margin-left: -20px;
// .icon {color: $dark; }
} }
.header-left { .header-left {
left: 0; @include transform-origin(center left);
padding-left: 10px; left: 0;
padding-left: 20px; padding-left: 10px;
padding-top: 20px;
} }
.header-right { .header-right {
right: 0; @include transform-origin(center right);
padding-right: 20px; right: 0;
padding-top: 20px; padding-right: 10px;
} }
.header-center { .header-center {
@include transform-origin(center center);
width: 100%; width: 100%;
left: 0; left: 0;
right: 0; right: 0;
@ -55,7 +56,7 @@
} }
} }
.header-left > * { margin-right: 10px; } .header-left > * { margin-right: 10px; }
.header-right > * { margin-left: 10px; } .header-right > * { margin-left: 5px; }
.header-right { font-size: 0;} .header-right { font-size: 0;}
.title { .title {
@ -89,3 +90,21 @@
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;
}
}

View File

@ -85,12 +85,3 @@
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);
}

View File

@ -1,52 +1,257 @@
@import "vars"; @import "vars";
#landing-header { #landing-header {
background-color: white; background-color: rgba(255,255,255,0.3);
height: 64px; height: 64px;
position: relative; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
} }
#landing { .landing-keyvisual-wrapper {
margin-top: 100px; background-image: url("../images/sd5-keyvisual-compressed.jpg");
background-size: cover;
section { background-position: center;
margin-left: 300px; padding-top: 40px;
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 {
margin-left: 300px; padding: 40px;
margin-top: 100px; padding-bottom: 80px;
margin-bottom: 100px; text-align: center;
color: $medium;
a {
margin-right: 20px;
}
} }
@media screen and (max-width: 1000px) {
#landing {
section {
margin-left: 20px;
margin-right: 20px;
}
}
.footer {
margin-left: 20px;
margin-right: 20px;
}
.header-right { @media screen and (min-width: 801px) {
right: auto; .plans-table-mobile {
padding-left: 10px; display: none;
padding-right: 20px; }
padding-top: 80px; }
}
@media screen and (max-width: 800px) {
#folder-wrapper {
padding-top: 128px; ul.lead.lead-xl, p.lead.lead-xl, ol.lead.lead-xl {
} font-size: 20px !important;
}
.header-right {
> span:first-child {
display: none;
}
}
.plans-table {
display: none;
}
.plans-table-mobile {
display: block;
tbody {
display: block;
width: 100%;
}
tr {
display: block;
width: 100%;
}
td, th {
display: block;
width: 100%;
}
ul, li {
width: 100%;
}
}
} }

View File

@ -2,6 +2,7 @@
@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;

View File

@ -59,9 +59,9 @@
} }
.close { .close {
margin-left: 44px; position: fixed;
margin-bottom: 44px; margin: 44px 44px;
.icon {display: block; } .icon {display: block; }
} }
figure { figure {
@ -135,6 +135,7 @@
outline: none; outline: none;
display: inline-block; display: inline-block;
text-align: left; text-align: left;
@include user-select(none);
border-radius: $radius*3; border-radius: $radius*3;
background-color: $light !important; background-color: $light !important;
@ -145,6 +146,7 @@
.modal-header { .modal-header {
padding: 30px 40px; padding: 30px 40px;
position: relative; position: relative;
color: $medium;
} }
.close-search { .close-search {
@ -277,5 +279,25 @@
// Footer (for actions) // Footer (for actions)
.modal-footer { .modal-footer {
margin-top: 20px; // border-bottom-left-radius: $radius;
} // border-bottom-right-radius: $radius;
// background-color: $dark !important;
// padding: 40px;
// padding-top: 0px;
// text-align: right; // right align buttons
@include clearfix(); // clear it in case folks use .pull-* classes on buttons
// Properly space out buttons
// .btn + .btn {
// margin-left: 5px;
// margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
// }
// // but override that for button groups
// .btn-group .btn + .btn {
// margin-left: -1px;
// }
// // and override it for block buttons as well
// .btn-block + .btn-block {
// margin-left: 0;
// }
}

14
styles/normalize.scss vendored
View File

@ -1,5 +1,17 @@
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */ /*! normalize.css v3.0.0 | MIT License | git.io/normalize */
//
// 1. Set default font family to sans-serif.
// 2. Prevent iOS text size adjust after orientation change, without disabling
// user zoom.
//
html {
font-family: sans-serif; // 1
-ms-text-size-adjust: 100%; // 2
-webkit-text-size-adjust: 100%; // 2
}
// //
// Remove default margin. // Remove default margin.
// //
@ -408,4 +420,4 @@ table {
td, td,
th { th {
padding: 0; padding: 0;
} }

View File

@ -27,5 +27,6 @@
right: 0; right: 0;
z-index: 800; z-index: 800;
pointer-events: none; pointer-events: none;
opacity: 0.25;
display: block; display: block;
} }

View File

@ -6,18 +6,22 @@
li { li {
&.checked { &.checked {
&:before {background-color: $medium !important; }
> a, > a,
> span { > span {
color: $medium;
} }
} }
&:hover { &:hover {
&:before {background-color: $medium; }
> a, > a,
> span { > span {
background-color: rgba(0,0,0,0.025) !important; background-color: rgba(0,0,0,0.025) !important;
} }
} }
&:before {background-color: $medium; }
> a, > a,
> span { > span {
color: $medium; color: $medium;
@ -26,7 +30,7 @@
} }
.select-list { .select-list {
&:empty:before { &:empty:before{
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
@ -41,14 +45,17 @@
opacity: 0.5; opacity: 0.5;
} }
-webkit-mask-image: -webkit-gradient(linear, left top, left 15px, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.5)));
background-clip: padding-box; background-clip: padding-box;
//font-size: 15px; font-size: 15px;
//line-height: 14px; line-height: 14px;
list-style: none; list-style: none;
margin: 0px; margin: 0px;
padding: 15px 0; padding: 15px 0;
text-align: left; text-align: left;
// background-color: $dark; // background-color: $dark;
color: $medium;
border-radius: $radius; border-radius: $radius;
.divider + li span {border: none !important; } .divider + li span {border: none !important; }
@ -83,11 +90,15 @@
} }
&:hover { &:hover {
background-color: black; // background-color: rgba(0,0,0,0.025);
&:before {
background-color: $medium;
display: block;
}
> a, > a,
> span { > span {
color: white; color: $medium;
color: $dark;
} }
} }
@ -115,8 +126,9 @@
display: block; display: block;
cursor: pointer; cursor: pointer;
white-space: nowrap; white-space: nowrap;
color: $medium;
margin: 0 25px; margin: 0 25px;
padding: 10px 0px; padding: 16px 3px;
// line-height: 50px; // line-height: 50px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -142,4 +154,4 @@
} }
} }
} }
} }

View File

@ -118,7 +118,7 @@
padding: 0 !important; padding: 0 !important;
.wrapper { .wrapper {
border: 4px solid black; border: 1px dotted rgba(128,128,128,0.5);
transition-duration: 0.25s; transition-duration: 0.25s;
transition-property: width, height, background-color; transition-property: width, height, background-color;
@ -132,27 +132,32 @@
max-height: 100%; max-height: 100%;
position: relative; position: relative;
overflow: scroll; overflow: scroll;
/** {
-moz-user-select: none !important; // firefox has selection problems
}*/
} }
.snap-ruler-h { .snap-ruler-h {
pointer-events: none; pointer-events: none;
position: fixed; position: fixed;
z-index: 2000; z-index: 0;
right: 0px; right: 0px;
height: 1px; height: 1px;
background-color: black; background-color: rgba(0,0,0,0.5);
left: 0px; left: 0px;
} }
.snap-ruler-v { .snap-ruler-v {
pointer-events: none; pointer-events: none;
position: fixed; position: fixed;
z-index: 2000; z-index: 0;
top: 0px; top: 0px;
bottom: 0px; bottom: 0px;
width: 1px; width: 1px;
background-color: black; background-color: rgba(0,0,0,0.5);
} }
.cursor { .cursor {
@ -222,12 +227,30 @@
} }
#space { #space {
// user-select: all; /*-webkit-user-select: all;
-ms-user-select: all;
-moz-user-select: all;
user-select: all;*/
position: relative; position: relative;
height: 100% !important; height: 100% !important;
//padding-top: 64px !important;
background-color: #eee; background-color: #eee;
} }
#made-with {
position: fixed;
width: 100%;
bottom: 0;
padding: 12px;
opacity: 0.25;
a {color: $dark; }
p {
text-align: center;
font-size: 11px;
}
}
#baseline { #baseline {
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -275,8 +298,8 @@
.space-bounds { .space-bounds {
position: absolute; position: absolute;
left: 0; left: 0px;
top: 0; top: 0px;
pointer-events: none; pointer-events: none;
background-size: cover; background-size: cover;
background-repeat: no-repeat; background-repeat: no-repeat;

View File

@ -65,15 +65,10 @@
html, html,
body { body {
height:100%; height:100%;
-webkit-tap-highlight-color: transparent;
background-color: white; background-color: white;
color: $black; background-color: $light;
} color: $darker;
body {
max-width: 100%;
padding: 0px;
text-rendering: optimizeLegibility;
cursor: default;
} }
*[contenteditable="true"] { *[contenteditable="true"] {
@ -86,12 +81,70 @@ body {
@include box-sizing(border-box); @include box-sizing(border-box);
} }
body {
max-width: 100%;
padding: 0px;
text-rendering: optimizeLegibility;
//@include user-select(none);
cursor: default;
}
.img img { .img img {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
/*.layer { .plan {
color: $medium;
border-radius: $radius;
display: inline-block;
padding: 30px;
background-color: transparent;
border: 2px solid rgba(0,0,0,0.05);
width: 100%;
&.active {
background-color: white;
border: none;
}
h4 {
color: black;
margin-bottom: 0px;
}
p {
font-size: 13px;
line-height: 1.4;
margin-top: 5px;
margin-bottom: 5px;
}
ul {
list-style: none;
font-size: 10px;
margin: 0px;
padding: 0px;
border-top: 2px solid rgba(0,0,0,0.05);
padding-top: 20px;
margin-top: 20px;
margin-bottom: 20px;
li {padding-top: 2px; }
}
}
#startup {
background-position: center;
background-image:url(/images/diamond.svg);
background-repeat: no-repeat;
}
#home {
background-color: white;
}
.layer {
@include transition( all 0.2s ease-in-out); @include transition( all 0.2s ease-in-out);
@include backface-visibility(hidden); @include backface-visibility(hidden);
position: absolute; position: absolute;
@ -119,7 +172,7 @@ body {
pointer-events: auto; pointer-events: auto;
opacity: 1; opacity: 1;
} }
}*/ }
[draggable] { [draggable] {
-moz-user-select: none; -moz-user-select: none;

View File

@ -8,9 +8,10 @@
} }
.table { .table {
width: 100%; width: 100%;
color: $medium;;
font-family: $main-font; font-family: $main-font;
border-radius: $radius; // border-radius: $radius;
border: 2px solid rgba(0,0,0,0.0125); // border: 2px solid rgba(0,0,0,0.0125) !important;
} }
.table thead > tr > th:first-child, .table thead > tr > th:first-child,

View File

@ -19,23 +19,50 @@
} }
margin: auto; margin: auto;
//text-align: center;
position: fixed; position: fixed;
top: 20px; bottom: 0px;
//width: 100%;
z-index: 3000; z-index: 3000;
padding: 0; padding: $gutter-b;
font-size: 0; font-size: 0;
line-height: 0; line-height: 0;
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15); transition-duration: 0.15s;
border: 1px solid black; transition-timing-function: ease-in-out;
border-radius: 5px; transition-delay: initial;
transition-property: opacity, transform;
// FIXME questionable? @include backface-visibility(hidden);
@include translate3d(0, 10px, 0);
pointer-events: none !important; pointer-events: none !important;
opacity: 0;
&.out {
@include translate3d(0, 10px, 0);
* {pointer-events: none !important; }
button, input, .dialog {
display: none;
}
}
&.in {
@include translate3d(0, 0, 0);
&.out {
@include translate3d(0, 10px, 0);
* {pointer-events: none !important; }
}
}
> * { > * {
margin: 0 2px;
margin-top: 4px;
pointer-events: auto !important; pointer-events: auto !important;
&.out {
margin: 0;
opacity: 0;
}
} }
&.toolbar-vertical { &.toolbar-vertical {
@ -160,6 +187,7 @@
} }
.toolbar-properties { .toolbar-properties {
bottom: 64px;
z-index: 0; z-index: 0;
&.in { &.in {
@ -168,12 +196,12 @@
.icon-sm { .icon-sm {
z-index: 110; z-index: 110;
//background-color: #222; background-color: #222;
border-radius: 50px; border-radius: 50px;
} }
.jewel { .jewel {
border: 2px solid #888; border: 2px solid rgba(255,255,255,0.5);
background-color: transparent; background-color: transparent;
color: #989898; color: #989898;
width: 36px; width: 36px;
@ -200,22 +228,5 @@
.toolbar-elements > .btn-group, .toolbar-elements > .btn-group,
.toolbar-properties > .btn-group { .toolbar-properties > .btn-group {
//box-shadow: 0 0 30px rgba(0,0,0,0.5); box-shadow: 0 0 30px rgba(0,0,0,0.5);
background-color: $white;
}
.toolbar-elements {
left: 20px;
}
.toolbar-properties {
right: 30px;
}
.zoom-bar {
position: absolute;
bottom: 30px;
right: 30px;
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
border: 1px solid black;
} }

View File

@ -33,7 +33,10 @@
@include translate3d(0, 0, 0); @include translate3d(0, 0, 0);
// @include backface-visibility(hidden); // @include backface-visibility(hidden);
perspective: 1000; -webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
.panel-toggles { .panel-toggles {
@include transition( all 0.15s ease-in-out); @include transition( all 0.15s ease-in-out);
@ -96,7 +99,10 @@
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
// @include backface-visibility(hidden); // @include backface-visibility(hidden);
perspective: 1000; -webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
z-index: 1000; z-index: 1000;

View File

@ -1,8 +1,6 @@
@import "vars"; @import "vars";
@import "mixins"; @import "mixins";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;900&display=swap');
body { body {
background-color: $light; background-color: $light;
color: $medium; color: $medium;
@ -27,7 +25,7 @@ hr {
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
color: inherit; color: inherit;
font-family: inherit; font-family: inherit;
font-weight: 900; font-weight: 500;
line-height: 1.3; line-height: 1.3;
margin-top: 0px; margin-top: 0px;
margin-bottom: 1em; margin-bottom: 1em;
@ -48,7 +46,8 @@ strong {font-weight: 500; }
small {font-size: 75%; } small {font-size: 75%; }
a { a {
color: black; text-decoration: none;
color: $medium;
} }
dl { dl {

View File

@ -9,6 +9,13 @@ $green: #2ecc71;
$red: #ff5955; $red: #ff5955;
$yellow: #f1c40f; $yellow: #f1c40f;
$light: #f5f5f5;
$lightish: #eee;
$facebook: #3e5b97;
$twitter: #2aa7de;
$color-1 : #4a2f7e; // purple $color-1 : #4a2f7e; // purple
$color-2 : #9b59b6; // lilac $color-2 : #9b59b6; // lilac
$color-3 : #3498db; // blue $color-3 : #3498db; // blue
@ -25,18 +32,15 @@ $black: #111; // black
$darker: #292929; $darker: #292929;
$dark: #222; // dark $dark: #222; // dark
$medium: #888; // medium $medium: #888; // medium
$light: #f5f5f5;
$lightish: #eee; // fixme
$lighter: #989898; $lighter: #989898;
$white: #ffffff;
$sidebar-width: 280px; $sidebar-width: 280px;
$main-font: Inter; $main-font: Avenir W01;
$sec-font: Inter; $sec-font: Avenir W01;
$font-size: 20px; $font-size: 18px;
$line-height: 1.5em; $line-height: 24px;
$gutter-a: 10px; $gutter-a: 10px;
$gutter-b: 20px; $gutter-b: 20px;
@ -44,4 +48,4 @@ $gutter-c: 40px;
$gutter-d: 60px; $gutter-d: 60px;
$gutter-e: 80px; $gutter-e: 80px;
$folder-gutter: 20px; $folder-gutter: 20px;

View File

@ -1,34 +1,62 @@
{% extends 'layouts/outer.html' %} {% extends 'layouts/outer.html' %}
{% block title %}Spacedeck{% endblock %} {% block title %}[[ __("welcome") ]]{% endblock %}
{% block content %} {% block content %}
<div id="landing"> <div id="landing">
<section> <div class="landing-keyvisual-wrapper">
<h1>Work Together, Visually.</h1> <div class="landing-box">
<p> <h2>[[__("landing_title")]]</h2>
Whenever you need to lay out pictures, text notes, video and audio clips on a blank canvas,
Spacedeck can help you. <p class="lead">
</p> <a href="/signup" class="btn btn-primary btn-block btn-xl">[[__("signup")]]</a>
<p> </p>
Spacedeck is a browser based application. It is the right tool for you if you want to quickly put together a collage of your idea or concept, either for yourself or to share it with teammembers, clients or students. Changes are updated in realtime.
</p> <p class="lead">
<p> <a href="/login" class="btn btn-primary btn-block btn-xl">[[__("login")]]</a>
Spacedeck is not meant for creating polished designs, but it is a good fit for: </p>
</p>
<ul> <p class="lead">
<li>Moodboards</li> [[__("landing_claim")]]
<li>Collages</li> </p>
<li>Teaching (Virtual Blackboards)</li>
<li>Shared Whiteboards</li> <p class="lead">
<li>Design Thinking</li> [[__("landing_example")]]
</ul> </p>
<img src="/images/sd6-screenshot.png" alt="Screenshot of Spacedeck 6.0">
<p> <ul>
The hosted version of Spacedeck 6.0 is currently in beta and invite only. You can also self-host and <a href="https://github.com/spacedeck/spacedeck-open">participate in the open source development</a>. <li class="lead">
</p> [[__("landing_features_1") | safe ]]
</section> </li>
<li class="lead">
[[__("landing_features_2") | safe ]]
</li>
<li class="lead">
[[__("landing_features_3") | safe ]]
</li>
<li class="lead">
[[__("landing_features_4") | safe ]]
</li>
<li class="lead">
[[__("landing_features_5") | safe ]]
</li>
<li class="lead">
[[__("landing_features_6") | safe ]]
</li>
<li class="lead">
[[__("landing_features_7") | safe ]]
</li>
</ul>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -9,25 +9,39 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link href="[[ '/images/favicon.png' | cdn ]]" rel="icon" type="image/x-icon" /> <link href="[[ '/images/favicon.png' | cdn ]]" rel="icon" type="image/x-icon" />
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,700,600,800,300|Montserrat:400,700|EB+Garamond|Vollkorn|Lato|Roboto|Source+Code+Pro|Ubuntu|Raleway|Playfair+Display|Crimson+Text' rel='stylesheet' type='text/css'>
<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>
<link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]"> <link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]">
<script> var csrf_token = '[[ csrf_token ]]'; </script> <script> var csrf_token = '[[ csrf_token ]]'; </script>
<!--script src="[[ '/javascripts/jquery-2.1.4.min.js' | cdn ]]"></script--> <script src="[[ '/javascripts/jquery-2.1.4.min.js' | cdn ]]"></script>
</head> </head>
<body> <body>
<!--[if lt IE 10]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<header id="landing-header" class="header"> <header id="landing-header" class="header">
<div class="header-left"> <div class="header-left">
<a class="btn btn-transparent btn-nude" href="[[config.endpoint]]/"><img src="[[ '/images/sd6-logo-black.svg' | cdn ]]" width="190"></a> <a class="btn btn-transparent btn-nude" href="[[config.endpoint]]/"><img src="[[ '/images/sd5-logo.svg' | cdn ]]" width="190"></a>
</div> </div>
<div class="header-right pull-right"> <div class="header-right pull-right">
{% if !user %} {% if !user %}
<span class="btn-group dark round">
{% if (locale != "de") %}<a href="/t/de" rel="alternate" hreflang="de" class="btn btn-transparent btn-md">Deutsch</a>{% endif %}
{% if (locale != "en") %}<a href="/t/en" rel="alternate" hreflang="en" class="btn btn-transparent btn-md">English</a>{% endif %}
{% if (locale != "fr") %}<a href="/t/fr" rel="alternate" hreflang="fr" class="btn btn-transparent btn-md">Français</a>{% endif %}
</span>
<a class="btn btn-md btn-dark btn-round" href="/login">[[__("login")]]</a> <a class="btn btn-md btn-dark btn-round" href="/login">[[__("login")]]</a>
<a class="btn btn-md btn-dark btn-round" href="/signup">[[__("signup")]]</a> <a class="btn btn-md btn-blue btn-round" href="/signup">[[__("signup")]]</a>
{% else %} {% else %}
<a class="btn btn-md btn-dark btn-round" href="/spaces">[[__("spaces")]]</a> <a class="btn btn-md btn-blue btn-round" href="/spaces">[[__("spaces")]]</a>
<a class="btn btn-md btn-dark btn-round" href="/logout">[[__("logout")]]</a> <a class="btn btn-md btn-dark btn-round" href="/logout">[[__("logout")]]</a>
{% endif %} {% endif %}
</div> </div>
@ -38,11 +52,8 @@
<div class="footer"> <div class="footer">
<p> <p>
<div class="col-xs-6"> <div class="col-xs-6">
&copy; 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br> <a href="/contact">[[ __("contact") ]]</a>
&copy; 2011–2019 Spacedeck GmbH (in liquidation)<br> <span style="color:#888">&copy; 2011–2018 The Spacedeck Open Developers <a href="https://github.com/spacedeck/spacedeck-open">https://github.com/spacedeck/spacedeck-open</a></span>
Source Code: <a href="https://github.com/mntmn/spacedeck-open">https://github.com/mntmn/spacedeck-open</a>
<br>
Font: <a href="https://rsms.me/inter/">Inter by rsms</a>
</div> </div>
</p> </p>
</div> </div>

View File

@ -1,30 +1,16 @@
<header id="dialog-header" class="header" v-if="(active_view == 'account' && user)" v-cloak> <div id="team" class="dialog in" style="padding:100px;z-index:20000;position:absolute;width:100%;min-height:100%;background-color:#eee" v-if="active_view == 'account' && user" v-cloak>
<div v-cloak class="header-left pull-left">
<a class="btn btn-dark btn-md btn-round btn-icon" href="/spaces">
<span class="icon icon-svg icon-sd6"></span>
</a>
<h5>Edit Account</h5>
</div>
<div class="header-right pull-right"> <a href="/spaces" class="btn btn-round btn-icon btn-dark btn-md pull-right" style="position:absolute;top:30px;right:30px"><span class="icon icon-cross-0"></span></a>
<a class="btn btn-dark btn-md btn-round btn-icon" href="/spaces">
<span class="icon icon-cross-0"></span>
</a>
</div>
</header>
<div class="dialog-freestanding dialog in" v-if="active_view == 'account' && user" v-cloak>
<div class="dialog-tabs" style="margin:auto"> <div class="dialog-tabs" style="margin:auto">
<div class="dialog-tab" v-bind:class="{open:account=='profile'}" v-on:click="account='profile'"><span>[[__("profile_caption")]]</span></div> <div class="dialog-tab" v-bind:class="{open:account=='profile'}" v-on:click="account='profile'"><span>[[__("profile_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='language'}" v-on:click="account='language'"><span>[[__("language_caption")]]</span></div> <div class="dialog-tab" v-bind:class="{open:account=='language'}" v-on:click="account='language'"><span>[[__("language_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='notifications'}" v-on:click="account='notifications'"><span>[[__("notifications_caption")]]</span></div> <div class="dialog-tab" v-bind:class="{open:account=='notifications'}" v-on:click="account='notifications'"><span>[[__("notifications_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='password'}" v-on:click="account='password'"><span>[[__("password_caption")]]</span></div> <div class="dialog-tab" v-if="user.account_type=='email'" v-bind:class="{open:account=='password'}" v-on:click="account='password'"><span>[[__("password_caption")]]</span></div>
<div class="dialog-tab" v-bind:class="{open:account=='terminate'}" v-on:click="account='terminate'"><span>[[__("terminate_caption")]]</span></div> <div class="dialog-tab" v-bind:class="{open:account=='terminate'}" v-on:click="account='terminate'"><span>[[__("terminate_caption")]]</span></div>
</div> </div>
<div class="dialog-section text-left"> <div class="dialog-section text-left" style="background-color:#f5f5f5;padding-top:40px;padding-bottom:40px">
<div class="collapse" v-bind:class="{in:account=='profile'}"> <div class="collapse" v-bind:class="{in:account=='profile'}">
<div class="labels-inline relative" style="margin-bottom:40px"> <div class="labels-inline relative" style="margin-bottom:40px">
<div class="form-group"> <div class="form-group">
@ -78,7 +64,29 @@
v-on:change="user.email_changed=true" v-on:change="user.email_changed=true"
placeholder="mail@example.com"> placeholder="mail@example.com">
<button class="btn btn-md btn-dark" v-on:click=" save_user()" style="margin-top:20px">Save</button> <button class="btn btn-md btn-darken" v-if="user.account_type=='email'" v-on:click=" save_user()" style="margin-top:20px">[[__("ok")]]</button>
</div>
<div class="form-group" v-if="!user.confirmed_at">
<p v-if="!user.confirmed_at && !account_confirmed_sent">[[__("confirmation_sent_long")]]</p>
<span
class="btn btn-xs btn-stroke-darken btn-round"
v-on:click=" confirm_again()"
v-if="!user.confirmed_at && !account_confirmed_sent"
>[[__("send_again")]]</span>
<p v-if="account_confirmed_sent">
<span class="icon icon-check"></span> <span>[[__("confirmation_sent_another")]]</span>
</p>
</div>
<div class="form-group">
<label class="label">Spacedeck.com Data Import</label>
<p v-if="!importables">No .ZIP files found in Spacedeck application folder.</p>
<ul>
<li v-for="f in importables">{{f}} <button v-on:click="start_zip_import(f)">Start Import</button></li>
</ul>
</div> </div>
</div> </div>
</div> </div>
@ -113,7 +121,7 @@
</div> </div>
<div class="collapse" v-bind:class="{in:account=='password'}"> <div class="collapse" v-bind:class="{in:account=='password'}">
<h4>Change Password</h4> <h4 class="modal-title">Change Password</h4>
<div class="modal-section labels-inline"> <div class="modal-section labels-inline">
<div class="form-group"> <div class="form-group">
<label class="label">[[__("current_password")]]</label> <label class="label">[[__("current_password")]]</label>
@ -132,36 +140,38 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="btn-cluster">
<button <button
class="btn btn-dark btn-md" class="btn btn-transparent btn-block"
v-on:click="save_user_password(password_change_current, password_change_new, password_change_new_confirmation);" > v-on:click="save_user_password(password_change_current, password_change_new, password_change_new_confirmation);" >
[[__("change_password")]] [[__("change_password")]]
</button> </button>
</div>
</div> </div>
</div> </div>
<div class="collapse" v-bind:class="{in:account=='terminate'}"> <div class="collapse" v-bind:class="{in:account=='terminate'}">
<h4>Terminate Account</h4> <div class="">
<div class="modal-section labels-inline"> <p>[[__("terminate_warning")]]</p>
<p>[[__("terminate_warning2")]]</p>
</div>
<div class="labels-inline" v-if="user.account_type == 'email'">
<div class="form-group"> <div class="form-group">
<label class="label">[[__("current_password")]]</label> <label class="label">[[__("current_password")]]</label>
<input v-model="account_remove_password" class="input input-white no-b" type="password"> <input v-model="account_remove_password" class="input input-white no-b" type="password">
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="label">[[__("terminate_reason")]]</label> <label class="label">[[__("terminate_reason")]]</label>
<textarea class="input input-white no-b" v-model="account_remove_feedback"></textarea> <textarea class="input input-white no-b" v-model="account_remove_feedback"></textarea>
<p class="message">[[__("terminate_reason_caption")]]</p> <p class="message">[[__("terminate_reason_caption")]]</p>
</div> </div>
</div>
<div class="modal-section labels-inline">
<div class="center alert alert-danger" v-if="account_remove_error">{{account_remove_error}}</div> <div class="center alert alert-danger" v-if="account_remove_error">{{account_remove_error}}</div>
</div> </div>
<div class="modal-footer"> <button class="btn btn-transparent btn-block" v-on:click="remove_account(account_remove_password, account_remove_feedback)">[[__("terminate_terminate")]]</button>
<button class="btn btn-stroke-darken btn-md" v-on:click="remove_account(account_remove_password, account_remove_feedback)">Terminate Account</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,23 +1,15 @@
<header id="folder-header" class="header" v-if="(active_view == 'folders' && active_folder)" v-cloak> <header id="folder-header" class="header" v-if="(active_view == 'folders' && active_folder)" v-cloak>
<div v-cloak class="header-left pull-left"> <div v-cloak class="header-left pull-left">
<a class="btn btn-dark btn-md btn-round btn-icon" href="/spaces"> <a class="btn btn-stroke-darken btn-md btn-round btn-icon" href="/spaces">
<span class="icon icon-svg icon-sd6"></span> <span class="icon icon-home"></span>
</a> </a>
<button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-dark btn-md btn-round" v-on:click="create_space('space')">[[ __('create_space') ]]</button> <button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-primary btn-md btn-round" v-on:click="create_space('space')">[[ __('create_space') ]]</button>
<button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-stroke-darken btn-md btn-round" v-on:click="create_space('folder')"> <button v-if="logged_in && (active_space_role == 'editor' || active_space_role == 'admin')" class="btn btn-stroke-darken btn-md btn-round" v-on:click="create_space('folder')">
<span>[[ __('create_folder') ]]</span> <span v-bind:class="{'disabled-pro':!is_pro(user)}">[[ __('create_folder') ]]</span>
</button> </button>
</div>
<label class="relative compact-hidden"> <div class="header-right pull-right">
<span class="icon icon-sm icon-zoom no-events absolute-top-left" style="margin: 5px;"></span>
<input id="folder-search"
type="search" name="search"
style="padding-left: 40px !important; margin-right: 10px;"
placeholder="[[ __('search') ]]"
class="input input-md input-white input-round no-b w-2"
v-model="folder_spaces_search" v-on:change="search_spaces">
</label>
<div class="dropdown top light m-r-20 compact-hidden" v-bind:class="{open : active_dropdown=='folder_sorting'}"> <div class="dropdown top light m-r-20 compact-hidden" v-bind:class="{open : active_dropdown=='folder_sorting'}">
<button class="btn btn-sm btn-nude" v-on:click="activate_dropdown('folder_sorting')"> <button class="btn btn-sm btn-nude" v-on:click="activate_dropdown('folder_sorting')">
<span>[[ __('sort_by') ]]</span>: <span>[[ __('sort_by') ]]</span>:
@ -41,15 +33,29 @@
v-on:click="set_folder_sorting('space_type',false)"> v-on:click="set_folder_sorting('space_type',false)">
<span>[[ __('type') ]]</span> <span>[[ __('type') ]]</span>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div>
<div class="header-right pull-right"> <label class="relative compact-hidden">
<span class="icon icon-sm icon-zoom no-events absolute-top-left" style="margin: 5px;"></span>
<input id="folder-search"
type="search" name="search"
style="padding-left: 40px !important; margin-right: 10px;"
placeholder="[[ __('search') ]]"
class="input input-md input-white input-round no-b w-2"
v-model="folder_spaces_search" v-on:change="search_spaces">
</label>
<button class="btn btn-stroke-darken btn-md btn-round" v-if="!user.confirmed_at" v-on:click="confirm_again()">
<span v-if="!account_confirmed_sent">[[ __('email_unconfirmed') ]]</span>
<span v-if="account_confirmed_sent">[[ __('confirmation_sent') ]]</span>
</button>
<div class="dropdown top right light" v-bind:class="{open: active_dropdown=='account'}"> <div class="dropdown top right light" v-bind:class="{open: active_dropdown=='account'}">
<button <button
class="profile-avatar btn btn-md btn-icon btn-dark btn-round" class="profile-avatar btn btn-md btn-icon btn-darken btn-round"
v-bind:style="background_image_style([user.avatar_thumb_uri])" v-bind:style="background_image_style([user.avatar_thumb_uri])"
v-bind:class="{'has-avatar-image':!!user.avatar_thumb_uri}" v-on:click="show_account();"> v-bind:class="{'has-avatar-image':!!user.avatar_thumb_uri}" v-on:click="show_account();">
<span class="icon icon-user" v-if="logged_in && !user.avatar_thumb_uri"></span></button> <span class="icon icon-user" v-if="logged_in && !user.avatar_thumb_uri"></span></button>
@ -70,6 +76,13 @@
</a> </a>
</li> </li>
<li v-on:click="activate_modal('support')">
<span>
<span class="icon icon-sm icon-info"></span>
<span>[[ __('support') ]]</span>
</span>
</li>
<li v-on:click="logout()"> <li v-on:click="logout()">
<span> <span>
<span class="icon icon-sm icon-logout"></span> <span class="icon icon-sm icon-logout"></span>
@ -81,12 +94,12 @@
</div> </div>
<!--div class="btn-group dark round" id="meta-toggle" style="margin-right:10px"> <div class="btn-group dark round" id="meta-toggle" style="margin-right:10px">
<button class="btn btn-md btn-transparent btn-icon btn-icon" v-on:click="toggle_meta()"> <button class="btn btn-md btn-transparent btn-icon btn-icon" v-on:click="toggle_meta()">
<span class="jewel" style="color: white; background-color: red" v-if="meta_unseen>0">{{meta_unseen}}</span> <span class="jewel" style="color: white; background-color: red" v-if="meta_unseen>0">{{meta_unseen}}</span>
<span class="icon icon-menu"></span> <span class="icon icon-menu"></span>
</button> </button>
</div--> </div>
</div> </div>
</header> </header>
@ -98,8 +111,10 @@
<div id="folder-breadcrumb"> <div id="folder-breadcrumb">
<span v-for="item in active_space_path" class="btn btn-sm btn-transparent" v-sd-droppable="handle_folder_drop;item"> <a v-for="item in active_space_path" type="button" class="btn btn-sm btn-transparent" href="/{{item.space_type}}s/{{item._id}}" v-sd-droppable="handle_folder_drop;item">
<a href="/{{item.space_type}}s/{{item._id}}">{{item.name}}</a>&nbsp; â–¶</span> <span>{{item.name}}</span>
<span class="seperator">/</span>
</a>
<a v-if="(active_space_role != 'admin')" type="button" class="btn btn-sm btn-transparent"> <a v-if="(active_space_role != 'admin')" type="button" class="btn btn-sm btn-transparent">
<span>{{active_folder.name}}</span> <span>{{active_folder.name}}</span>
@ -113,10 +128,12 @@
<ul class="select-list"> <ul class="select-list">
<li><span class="tile-rename" v-on:click="rename_folder(active_folder)">[[__("rename")]]</span></li> <li><span class="tile-rename" v-on:click="rename_folder(active_folder)">[[__("rename")]]</span></li>
<li v-if="active_space_role == 'admin'"><span class="tile-share" v-on:click="activate_access()">[[__("share")]]</span></li> <li v-if="active_space_role == 'admin'"><span class="tile-share" v-on:click="activate_access()">[[__("share")]]</span></li>
<li><a v-on:click=" open_url('[[config.endpoint]]/api/spaces/'+active_folder._id+'/list')" target="_blank">[[__("list")]]</a></li>
</ul> </ul>
</div> </div>
</div> </div>
<div v-if="active_folder._id == user.home_folder_id"> <div v-if="active_folder._id == user.home_folder_id">
<span>[[ __('home') ]]</span> <span>[[ __('home') ]]</span>
</div> </div>
@ -129,6 +146,7 @@
</div> </div>
</div> </div>
<div id="folder-empty" v-if="folder_spaces_filter"> <div id="folder-empty" v-if="folder_spaces_filter">
<div v-if="active_profile_spaces | empty?"> <div v-if="active_profile_spaces | empty?">
<p><b>"{{folder_spaces_filter}}"</b> <br/>[[ __('search_no_results') ]]</p> <p><b>"{{folder_spaces_filter}}"</b> <br/>[[ __('search_no_results') ]]</p>
@ -156,6 +174,7 @@
<div class="dropdown-menu" role="menu"> <div class="dropdown-menu" role="menu">
<ul class="select-list"> <ul class="select-list">
<li v-on:click="duplicate_space(item)"><span><span class="icon icon-sm icon-duplicate"></span>[[ __('duplicate') ]]</span></li>
<li v-on:click="rename_space(item)"><span><span class="icon icon-sm icon-tag"></span>[[ __('rename') ]]</span></li> <li v-on:click="rename_space(item)"><span><span class="icon icon-sm icon-tag"></span>[[ __('rename') ]]</span></li>
<li v-on:click="delete_space(item)"><span><span class="icon icon-sm icon-trash"></span>[[ __('delete') ]]</span></li> <li v-on:click="delete_space(item)"><span><span class="icon icon-sm icon-trash"></span>[[ __('delete') ]]</span></li>
</ul> </ul>

View File

@ -1,11 +1,17 @@
<header id="landing-header" class="header" v-cloak v-if="(active_view == 'login' || active_view == 'signup' || active_view == 'password-reset' || active_view == 'password-confirm')"> <header id="landing-header" class="header" v-cloak v-if="(active_view == 'login' || active_view == 'signup' || active_view == 'password-reset' || active_view == 'password-confirm')">
<div class="header-left"> <div class="header-left">
<a class="btn btn-transparent btn-nude" href="/"><img src="/images/sd6-logo-black.svg" width="190"></a> <a class="btn btn-transparent btn-nude" href="/"><img src="/images/sd5-logo.svg" width="190"></a>
</div> </div>
<div class="header-right pull-right"> <div class="header-right pull-right">
<a v-if="active_view != 'login'" class="btn btn-md btn-dark btn-round" href="/login">[[__("login")]]</a> <span class="btn-group dark round">
<a v-if="active_view != 'signup'" class="btn btn-md btn-dark btn-round" href="/signup">[[__("signup")]]</a> {% if (locale != "de") %}<a href="/t/de?r={{active_view}}" class="btn btn-transparent btn-md">Deutsch</a>{% endif %}
{% if (locale != "en") %}<a href="/t/en?r={{active_view}}" class="btn btn-transparent btn-md">English</a>{% endif %}
{% if (locale != "fr") %}<a href="/t/fr?r={{active_view}}" class="btn btn-transparent btn-md">Français</a>{% endif %}
</span>
<a class="btn btn-md btn-dark btn-round" href="/login">[[__("login")]]</a>
<a class="btn btn-md btn-blue btn-round" href="/signup">[[__("signup")]]</a>
</div> </div>
</header> </header>
@ -17,7 +23,10 @@
<div id="login" v-bind:class="{active : active_view == 'login'}"> <div id="login" v-bind:class="{active : active_view == 'login'}">
<div class="content"> <div class="content">
<form v-on:submit="login_submit(user_forms_email, login_password, $event)"> <form v-on:submit="login_submit(user_forms_email, login_password, $event)">
<h3>Login</h3>
<span class="btn btn-xs btn-darken pull-right" v-on:click="login_google();">[[__("login_google")]]</span>
<h4>[[__("login")]]</h4>
<div class="tight"> <div class="tight">
<div class="form-group"> <div class="form-group">
@ -28,15 +37,16 @@
</div> </div>
</div> </div>
<button type="submit" class="btn btn-dark btn-block"> <button type="submit" class="btn btn-primary btn-block">
<span v-show="!loading_user">Login</span> <span v-show="!loading_user">[[__("login")]]</span>
<span v-show="loading_user">Logging in…</span> <span v-show="loading_user">[[__("logging_in")]]</span>
</button> </button>
<div class="center alert alert-danger" v-if="login_error">{{login_error}}</div> <div class="center alert alert-danger" v-if="login_error">{{login_error}}</div>
<div style="margin-top:2em"> <div class="pull-right">
<a href="/password-reset">Forgot Password</a> <a class="btn btn-xs btn-darken" href="/signup">[[__("signup")]]</a>&nbsp;
<a class="btn btn-xs btn-darken" href="/password-reset">[[__("reset_password")]]</a>
</div> </div>
</form> </form>
</div> </div>
@ -44,12 +54,23 @@
<div id="signup" v-bind:class="{active : active_view == 'signup'}"> <div id="signup" v-bind:class="{active : active_view == 'signup'}">
<div class="content"> <div class="content">
<form v-on:submit="signup_submit($event, user_forms_name, user_forms_email, signup_password, signup_password_confirmation, signup_invite_code)"> <form v-on:submit="signup_submit($event, user_forms_name, user_forms_email, signup_password, signup_password_confirmation)">
<span class="btn btn-xs btn-darken pull-right" v-on:click="login_google();">[[__("login_google")]]</span>
<h4>[[__("signup")]]</h4> <h4>[[__("signup")]]</h4>
<div class="tight"> <div class="tight">
<div class="form-group"> <div class="form-group">
<input class="input" type="email" required id="user-email" v-model="user_forms_email" placeholder="[[__("email")]]" autofocus v-focus> <input class="input" type="text" id="user-name" v-model="user_forms_name" placeholder="[[__("name")]]" v-focus autofocus>
</div>
</div>
<div class="tight">
<div class="form-group">
<input class="input" type="email" required id="user-email" v-model="user_forms_email" placeholder="[[__("email")]]">
</div> </div>
<div class="form-group"> <div class="form-group">
@ -57,33 +78,21 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<input class="input" id="user-password-confirmation" required type="password" v-model="signup_password_confirmation" placeholder="Repeat Password"> <input class="input" id="user-password-confirmation" required type="password" v-model="signup_password_confirmation" placeholder="[[__("password_confirmation")]]">
</div> </div>
</div> </div>
<div class="tight">
<div class="form-group">
<input class="input" type="text" id="user-name" v-model="user_forms_name" placeholder="Pick a username">
</div>
<!--
Disabled textbox so people don't have to input beta code when registering.
Remember to also set invite_code to an empty string ("") in /config/default.conf!
<div class="form-group">
<input class="input" id="invite-code" required type="text" v-model="signup_invite_code" placeholder="Beta Invite Code">
</div>-->
</div>
<!--div style="margin-top: -7px; margin-bottom: 7px;"><small>By signing up you agree to our <a href="/terms" target="_blank">TOS</a> and <a href="/privacy" target="_blank">Privacy Policy.</a></small><br/> <div style="margin-top: -7px; margin-bottom: 7px;"><small>By signing up you agree to our <a href="/terms" target="_blank">TOS</a> and <a href="/privacy" target="_blank">Privacy Policy.</a></small><br/>
</div--> </div>
<button class="btn btn-dark btn-block"> <button class="btn btn-primary btn-block">
<span v-if="!creating_user">[[__("signup")]]</span> <span v-if="!creating_user">[[__("signup")]]</span>
<span v-if="creating_user">[[__("signing_up")]]</span> <span v-if="creating_user">[[__("signing_up")]]</span>
</button> </button>
<div class="center alert alert-danger" style="width:100%;" v-if="signup_error">{{signup_error}}</div> <div class="center alert alert-danger" style="width:100%;" v-if="signup_error">{{signup_error}}</div>
<a class="btn btn-link btn-block" href="/login" style="margin-top: 20px">[[__("login")]]</a>
</form> </form>
</div> </div>
</div> </div>
@ -98,12 +107,12 @@
</div> </div>
</div> </div>
<div class="text-center alert alert-danger" v-if="password_reset_error">{{password_reset_error}}</div> <div class="text-center alert alert-danger" v-if="password_reset_error">{{password_reset_error}}</div>
<button class="btn btn-dark btn-block" v-on:click="password_reset_submit($event, reset_email)">[[__("reset_password")]]</button> <button class="btn btn-primary btn-block" v-on:click="password_reset_submit($event, reset_email)">[[__("reset_password")]]</button>
</form> </form>
</div> </div>
<div class="content" v-if="password_reset_send==true"> <div class="content" v-if="password_reset_send==true">
<h4>Reset Password</h4> <h4>[[__("password_confirmation")]]</h4>
Please check your email inbox. [[__("password_check_inbox")]]
</div> </div>
</div> </div>
@ -114,16 +123,16 @@
<div class="tight"> <div class="tight">
<div class="form-group"> <div class="form-group">
<input class="input" id="user-password" type="password" v-model="signup_password" placeholder="New Password"> <input class="input" id="user-password" type="password" v-model="signup_password" placeholder="[[__("password")]]">
</div> </div>
<div class="form-group"> <div class="form-group">
<input class="input" id="user-password" type="password" v-model="signup_password_confirmation" placeholder="Repeat Password"> <input class="input" id="user-password" type="password" v-model="signup_password_confirmation" placeholder="[[__("password_confirmation")]]">
</div> </div>
</div> </div>
<div class="text-center alert alert-danger" v-if="password_reset_confirm_error">{{password_reset_confirm_error}}</div> <div class="text-center alert alert-danger" v-if="password_reset_confirm_error">{{password_reset_confirm_error}}</div>
<button class="btn btn-dark btn-block" v-on:click="password_reset_confirm($event, signup_password, signup_password_confirmation)">[[__("save")]]</button> <button class="btn btn-primary btn-block" v-on:click="password_reset_confirm($event, signup_password, signup_password_confirmation)">[[__("save")]]</button>
</form> </form>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content" style="width:760px"> <div class="modal-content" style="width:760px">
<div class="modal-header" style="padding-bottom:0"> <div class="modal-header" style="padding-bottom:0">
<h3 class="text-left">[[__("share")]]: {{access_settings_space.name}}</h3> <h3 class="text-left"><span class="icon icon-share icon-sm"></span> [[__("share")]]: {{access_settings_space.name}}</h3>
<button type="button" class="btn btn-icon btn-light btn-round close" v-on:click=" close_modal()"> <button type="button" class="btn btn-icon btn-light btn-round close" v-on:click=" close_modal()">
<span class="icon icon-cross-1"></span> <span class="icon icon-cross-1"></span>
</button> </button>
@ -68,7 +68,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<button class="btn btn-primary btn-md" v-on:click="invite_member(access_settings_space, invite_email, invite_message, invite_member_role)"> [[__("invite")]] </button> <button class="btn btn-primary btn-md btn-round" v-on:click="invite_member(access_settings_space, invite_email, invite_message, invite_member_role)"> [[__("invite")]] </button>
</div> </div>
</div> </div>
@ -85,19 +85,14 @@
</tr> </tr>
<tr v-for="member in access_settings_memberships" v-bind:class="member.state"> <tr v-for="member in access_settings_memberships" v-bind:class="member.state">
<td> <td>
<span class="editor-avatar btn btn-md btn-dark btn-icon btn-round" <span class="editor-avatar btn btn-xs btn-round btn-icon" v-if="member.user">{{member.user.initials}}</span>
v-if="member.user" <span class="editor-avatar btn btn-xs btn-round btn-icon icon-hourglass" v-if="!member.user"></span>
v-bind:style="background_image_style([member.user.avatar_thumb_uri])"
v-bind:class="{'has-avatar-image':!!member.user.avatar_thumb_uri}">
<span class="icon icon-user" v-if="!member.user.avatar_thumb_uri"></span>
</span>
<span class="editor-avatar btn btn-md btn-round btn-icon icon-hourglass" v-if="!member.user"></span>
</td> </td>
<td> <td>
<span class="editor-name" v-if="member.user && member.state == 'active'">{{member.user.nickname}}</span> <span class="editor-email" v-if="member.state == 'active'">{{member.user.email}}</span>
<span class="editor-email" v-if="!member.user || member.state == 'pending'">(pending)</span> <span class="editor-email" v-if="member.state == 'pending'">{{member.email_invited}}</span>
<span class="editor-email" v-if="member.user && member.state == 'active'">({{member.user.email}})</span> <span class="editor-name" v-if="member.state == 'active'">{{member.user.nickname}}</span>
<span class="editor-email" v-if="!member.user || member.state == 'pending'">({{member.email_invited}})</span> <span class="editor-email" v-if="member.state == 'pending'">(pending)</span>
</td> </td>
<td> <td>
<div class="form-group"> <div class="form-group">
@ -118,7 +113,7 @@
</p> </p>
<div class="form-group" style="padding-top: 40px"> <div class="form-group" style="padding-top: 40px">
<button class="btn btn-primary btn-md" v-on:click="close_modal();"> [[__("ok")]] </button> <button class="btn btn-primary btn-md btn-round" v-on:click="close_modal();"> [[__("ok")]] </button>
</div> </div>
</div> </div>

View File

@ -1,3 +1,131 @@
<!-- FIXME modal -->
<div class="modal" v-if="(duplicate_folders.length > 0)" v-cloak>
<div class="modal-wrapper">
<div class="modal-dialog">
<button type="button" class="btn btn-icon btn-light btn-round close" v-on:click="duplicate_folders = []">
<span class="icon icon-cross-1"></span>
</button>
<div class="modal-content">
<div class="modal-body labels-inline">
<div class="modal-section">
<div class="form-group">
<label>
[[__("duplicate_destination")]]
</label>
</div>
<div class="form-group">
<select v-on:change="duplicate_folder_id=$event.target.value">
<option v-for="f in duplicate_folders" value="{{f._id}}">{{f.name}}</option>
</select>
</div>
<div class="form-group">
<button class="btn btn-md btn-round btn-primary" v-on:click="duplicate_folder_confirm(); ">
<span class="icon-label">[[__("ok")]]</span>
</button>
<button class="btn btn-md btn-round btn-darken pull-right" v-on:click="duplicate_folders = [];">
<span class="icon-label">[[__("cancel")]]</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-cloak class="header-left" v-show="active_space_loaded">
<div class="btn-group dark">
<div class="pull-left">
<a
class="btn btn-stroke-darken btn-md btn-round btn-icon"
title="[[__("home")]]" href="/spaces"
v-if="(logged_in && !embedded && !active_space.parent_space_id && !guest_nickname)">
<span class="icon icon-home"></span>
</a>
<a
class="btn btn-stroke-darken btn-md btn-round btn-icon"
title="[[__("parent_folder")]]"
href="/folders/{{active_space.parent_space_id}}"
v-if="(active_space.parent_space_id && !guest_nickname)">
<span class="icon icon-arrow-left-light"></span>
</a>
<input class="input input-md input-transparent w-auto"
id="space-title"
v-model="active_space.name" name="title" v-on:keydown="save_space_keydown($event)"
v-if="space_editing_title && logged_in" style="padding-right:0" v-focus>
<span class="input input-md input-transparent w-auto"
v-if="!space_editing_title && logged_in"
v-on:click="edit_space_title()">{{active_space.name}}</span>
<span v-if="!logged_in" class="btn btn-dark btn-round btn-md">{{active_space.name}}</span>
<button class="btn btn-md btn-transparent btn-icon" v-if="space_editing_title" v-on:click="save_space_keydown()">
<span class="icon icon-check"></span>
</button>
<div class="dropdown top left light" v-bind:class="{open: active_dropdown=='space'}">
<button class="btn btn-md btn-icon btn-dark" v-on:click="activate_dropdown('space')">
<span class="icon icon-triangle-down"></span></button>
<div class="dropdown-menu" role="menu">
<ul class="select-list">
<li v-on:click="activate_access()" v-if="logged_in">
<span>
<span class="icon icon-sm icon-share"></span>
<span>[[ __('share') ]]</span>
</span>
</li>
<li v-on:click="edit_space_title()" v-if="logged_in">
<span>
<span class="icon icon-sm icon-tag"></span>
<span>[[ __('rename') ]]</span>
</span>
</li>
<li v-on:click="duplicate_space_into_folder()" v-if="logged_in">
<span>
<span class="icon icon-sm icon-duplicate"></span>
<span>[[ __('duplicate') ]]</span>
</span>
</li>
<li v-on:click="download_space()">
<span>
<span class="icon icon-sm icon-download"></span>
<span>[[ __('download_space') ]]</span>
</span>
</li>
<li v-on:click="activate_modal('support')" v-if="logged_in">
<span>
<span class="icon icon-sm icon-info"></span>
<span>[[ __('support') ]]</span>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<span class="btn btn-red btn-md" id="offline-indicator" v-bind:class="{offline: was_offline}" v-on:click="show_offline_help()">[[__("offline")]]</span>
</div>
<div v-cloak class="header-right" v-if="active_space_loaded"> <div v-cloak class="header-right" v-if="active_space_loaded">
<span v-for="active_user in active_space_users" > <span v-for="active_user in active_space_users" >
@ -12,8 +140,14 @@
</button> </button>
</span> </span>
<div class="btn-group dark" v-if="active_space_role!='viewer'">
<button class="btn btn-md btn-transparent btn-icon" title="Start Presentation (others follow what you see)" v-on:click="toggle_present_mode()" v-bind:class="{open:present_mode}">
<span class="icon icon-presentation"></span>
</button>
</div>
<div class="btn-group light round" v-if="zones.length"> <div class="btn-group dark round" v-if="zones.length">
<button class="btn btn-md btn-transparent btn-icon" v-on:click="go_to_previous_zone()" title="[[__("Previous Zone")]]"> <button class="btn btn-md btn-transparent btn-icon" v-on:click="go_to_previous_zone()" title="[[__("Previous Zone")]]">
<span class="icon icon-triangle-4-left"></span> <span class="icon icon-triangle-4-left"></span>
</button> </button>
@ -24,13 +158,17 @@
<span class="icon icon-triangle-4-right"></span> <span class="icon icon-triangle-4-right"></span>
</button> </button>
</div> </div>
<!--button class="btn btn-md btn-dark btn-round btn-icon" v-on:click="download_space()" title="[[__("download_space")]]">
<span class="icon icon-download"></span>
</button-->
<!--div class="btn-group light" id="meta-toggle" style="margin-right:10px"> <div class="btn-group dark" id="meta-toggle" style="margin-right:10px">
<button class="btn btn-md btn-transparent btn-icon" v-on:click="toggle_meta()" title="[[__("chat")]]"> <button class="btn btn-md btn-transparent btn-icon" v-on:click="toggle_meta()" title="[[__("chat")]]">
<span class="jewel" style="color: white; background-color: red" v-if="meta_unseen>0">{{meta_unseen}}</span> <span class="jewel" style="color: white; background-color: red" v-if="meta_unseen>0">{{meta_unseen}}</span>
<span class="icon icon-messages"></span> <span class="icon icon-messages"></span>
</button> </button>
</div--> </div>
</div> </div>
{% include "./tool/toolbar-elements.html" %} {% include "./tool/toolbar-elements.html" %}
@ -43,8 +181,9 @@
<div class="space-empty" v-cloak v-if="active_view == 'space' && !present_mode && active_space_artifacts.length == 0"> <div class="space-empty" v-cloak v-if="active_view == 'space' && !present_mode && active_space_artifacts.length == 0">
<div class="table-fake"> <div class="table-fake">
<div class="cell"> <div class="cell">
<p>Use the toolbar to add content.<br> <p>Click anywhere to add content.<br>
You can also drop images or sound and video files.</p> You can also drop images, sounds and video<br>
or use copy and paste.</p>
</div> </div>
</div> </div>
</div> </div>
@ -67,7 +206,7 @@
<div id="space-clipboard" style="position:fixed;top:0;left:0;z-index:0;opacity:0;background-color:white"><textarea v-model="selected_artifacts_json" cols="2" rows="2" id="clipboard-ta" class="mousetrap"></textarea></div> <div id="space-clipboard" style="position:fixed;top:0;left:0;z-index:0;opacity:0;background-color:white"><textarea v-model="selected_artifacts_json" cols="2" rows="2" id="clipboard-ta" class="mousetrap"></textarea></div>
<div class="space-bounds" v-bind:style="{width: (active_space.width*bounds_zoom+1000) + 'px', height: (active_space.height*bounds_zoom+1000) + 'px', 'background-color': active_space.background_color}"></div> <div class="space-bounds" v-bind:style="{width: active_space.width*bounds_zoom + 'px', height: active_space.height*bounds_zoom + 'px', 'background-color': active_space.background_color}"></div>
<div class="wrapper" <div class="wrapper"
v-bind:style="{ v-bind:style="{
@ -105,6 +244,7 @@
<a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a> <a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a>
</span> </span>
<div class="btn btn-xs btn-icon btn-round btn-primary edit" v-show="editing_artifact_id!=a._id && is_selected(a)" v-on:touchstart="delayed_edit_artifact($event)"><span class="icon icon-pencil" v-on:click="toggle_selected_artifact_editing(true)" v-on:"touchstart:delayed_edit_artifact($event)"></span></div>
<input v-show="is_selected(a)" type="text" id="ios-focuser-{{a._id}}" class="ios-focuser"> <input v-show="is_selected(a)" type="text" id="ios-focuser-{{a._id}}" class="ios-focuser">
</div> </div>
@ -126,6 +266,7 @@
<a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a> <a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a>
</span> </span>
<div class="btn btn-xs btn-icon btn-round btn-primary edit" v-show="editing_artifact_id!=a._id && is_selected(a)" v-on:touchstart="delayed_edit_artifact($event)"><span class="icon icon-pencil" v-on:click="toggle_selected_artifact_editing(true)" v-on:"touchstart:delayed_edit_artifact($event)"></span></div>
<input v-show="is_selected(a)" type="text" id="ios-focuser-{{a._id}}" class="ios-focuser"> <input v-show="is_selected(a)" type="text" id="ios-focuser-{{a._id}}" class="ios-focuser">
</div> </div>
@ -145,6 +286,11 @@
<source v-for="rep in a.payload_alternatives" v-bind:src="rep.payload_uri" v-bind:type="rep.mime" /> <source v-for="rep in a.payload_alternatives" v-bind:src="rep.payload_uri" v-bind:type="rep.mime" />
</video> </video>
<a class="btn btn-md btn-icon btn-round btn-primary edit"
v-show="a.mime == 'application/pdf'"
v-bind:href="a.payload_uri" target="_blank"
><span class="icon icon-link"></span></a>
<span v-if="a.view.link.length>0" class="link-wrapper"> <span v-if="a.view.link.length>0" class="link-wrapper">
<a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a> <a class="link btn btn-round btn-primary btn-sm" v-if="a.view.link" v-bind:href="a.view.link" target="_blank">{{a.view.link_caption}}</a>
</span> </span>
@ -317,7 +463,7 @@
</div> </div>
<div v-if="active_space_loaded" v-cloak> <div v-if="active_space_loaded" v-cloak>
<!--div id="minimap" <div id="minimap"
v-bind:style="{width: ''+(active_space.width/minimap_scale)+'px', height: ''+(active_space.height/minimap_scale)+'px', bottom: '66px', right: '20px'}" v-bind:style="{width: ''+(active_space.width/minimap_scale)+'px', height: ''+(active_space.height/minimap_scale)+'px', bottom: '66px', right: '20px'}"
v-if="active_space" v-if="active_space"
v-on:mousedown="handle_minimap_mousedown($event)" v-on:mousedown="handle_minimap_mousedown($event)"
@ -329,16 +475,17 @@
v-on:mouseup="handle_minimap_mouseup($event)"> v-on:mouseup="handle_minimap_mouseup($event)">
<div v-for="a in active_space_artifacts" v-bind:style="{left: ''+(a.x/minimap_scale)+ 'px', top: ''+(a.y/minimap_scale) + 'px', width: ''+(a.w/minimap_scale)+ 'px', height: ''+(a.h/minimap_scale) + 'px'}"></div> <div v-for="a in active_space_artifacts" v-bind:style="{left: ''+(a.x/minimap_scale)+ 'px', top: ''+(a.y/minimap_scale) + 'px', width: ''+(a.w/minimap_scale)+ 'px', height: ''+(a.h/minimap_scale) + 'px'}"></div>
<div class="window" v-bind:style="{left: ''+(scroll_left/minimap_scale) + 'px', top: ''+(scroll_top/minimap_scale)+ 'px', width: ''+(window_width/minimap_scale)+ 'px', height: ''+(window_height/minimap_scale) + 'px'}"></div> <div class="window" v-bind:style="{left: ''+(scroll_left/minimap_scale) + 'px', top: ''+(scroll_top/minimap_scale)+ 'px', width: ''+(window_width/minimap_scale)+ 'px', height: ''+(window_height/minimap_scale) + 'px'}"></div>
</div-->
<div class="btn-group light zoom-bar"> </div>
<button class="btn btn-icon btn-md btn-white" v-on:click="zoom_in()">
<div class="btn-group dark" style="position:absolute;bottom:20px;right:20px;">
<button class="btn btn-icon btn-md btn-transparent" v-on:click="zoom_in()">
<span class="icon icon-plus"></span> <span class="icon icon-plus"></span>
</button> </button>
<button class="btn btn-md btn-white no-p" v-on:click="zoom_to_original()"> <button class="btn btn-md btn-transparent no-p" v-on:click="zoom_to_original()">
{{viewport_zoom_percent}}% {{viewport_zoom_percent}}%
</button> </button>
<button class="btn btn-icon btn-md btn-white" v-on:click="zoom_out()"> <button class="btn btn-icon btn-md btn-transparent" v-on:click="zoom_out()">
<span class="icon icon-minus"></span> <span class="icon icon-minus"></span>
</button> </button>
</div> </div>

View File

@ -126,11 +126,19 @@
<label class="label label-sm text-center">[[__("font_size")]]</label> <label class="label label-sm text-center">[[__("font_size")]]</label>
<input class="input no-b no-p text-center text-large" spellcheck="false" type="text" pattern="[0-9]" maxlength="64" v-model="active_style.font_size"> <input class="input no-b no-p text-center text-large" spellcheck="false" type="text" pattern="[0-9]" maxlength="64" v-model="active_style.font_size">
<button tabindex="-1" class="input-drag btn btn-transparent btn-icon" style="cursor: ns-resize;" v-sd-fader="true" sd-fader-var-y="active_style.font_size" sd-fader-min-y="30" sd-fader-max-y="200" sd-fader-sens="5"> <!--button tabindex="-1" class="input-drag btn btn-transparent btn-icon" style="cursor: ns-resize;" v-sd-fader="true" sd-fader-var-y="active_style.font_size" sd-fader-min-y="8" sd-fader-max-y="400" sd-fader-sens="0.2">
<span class="icon icon-triangles-vertical"></span> <span class="icon icon-triangles-vertical"></span>
</button> </button-->
<span class="input-unit">px</span> <span class="input-unit">px</span>
</div> </div>
<div class="form-group no-m">
<span class="font-size-swatches" v-show="opened_dialog=='color-text'">
<button class="btn btn-sm" v-on:click="apply_font_size(64)" style="font-size:32px">Big</button>
<button class="btn btn-sm" v-on:click="apply_font_size(32)" style="font-size:24px">Medium</button>
<button class="btn btn-sm" v-on:click="apply_font_size(18)" style="font-size:14px">Small</button>
</span>
</div>
<!--div class="form-group no-m"> <!--div class="form-group no-m">
<label class="label label-sm text-center">[[__("line_height")]]</label> <label class="label label-sm text-center">[[__("line_height")]]</label>

View File

@ -1,5 +1,5 @@
<div id="layout" class="relative"> <div id="layout" class="relative">
<div class="dialog-section"> <div class="dialog-section no-p-b">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-transparent btn-icon" v-on:click="layout_stack_top()"> <button class="btn btn-transparent btn-icon" v-on:click="layout_stack_top()">
<span class="icon icon-stack-3d-top"></span> <span class="icon icon-stack-3d-top"></span>

View File

@ -1,48 +1,69 @@
<h4 class="dialog-title">[[__("tool_shape")]]</h4> <h4 class="dialog-title">[[__("tool_shape")]]</h4>
<div id="shapes"> <div id="shapes">
<div class="dialog-section"> <div class="dialog-section no-p-h" style="white-space: normal;">
<div class="btn-group"> <button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('ellipse',$event)">
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('ellipse',$event)"> <span class="icon icon-shape-circle"></span>
<span class="icon icon-shape-circle"></span> <span class="icon-label">[[__("tool_circle")]]</span>
<span class="icon-label">[[__("tool_circle")]]</span> </button>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('hexagon',$event)">
<span class="icon icon-shape-hexagon"></span>
<span class="icon-label">[[__("tool_hexagon")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('square',$event)">
<span class="icon icon-shape-square"></span>
<span class="icon-label">[[__("tool_square")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('speechbubble',$event)">
<span class="icon icon-shape-bubble"></span>
<span class="icon-label">[[__("tool_bubble")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('cloud',$event)">
<span class="icon icon-shape-cloud"></span>
<span class="icon-label">[[__("tool_cloud")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('burst',$event)">
<span class="icon icon-shape-burst"></span>
<span class="icon-label">[[__("tool_burst")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('star',$event)">
<span class="icon icon-shape-star"></span>
<span class="icon-label">[[__("tool_star")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('heart',$event)">
<span class="icon icon-shape-heart"></span>
<span class="icon-label">[[__("tool_heart")]]</span>
</button>
</div> <button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('hexagon',$event)">
<span class="icon icon-shape-hexagon"></span>
<span class="icon-label">[[__("tool_hexagon")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('square',$event)">
<span class="icon icon-shape-square"></span>
<span class="icon-label">[[__("tool_square")]]</span>
</button>
<!--button class="btn btn-icon-labeled btn-transparent rot45" v-on:click="add_shape('diamond',$event)">
<span class="icon icon-shape-square"></span>
<span class="icon-label">[[__("tool_diamond")]]</span>
</button-->
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('speechbubble',$event)">
<span class="icon icon-shape-bubble"></span>
<span class="icon-label">[[__("tool_bubble")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('cloud',$event)">
<span class="icon icon-shape-cloud"></span>
<span class="icon-label">[[__("tool_cloud")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('burst',$event)">
<span class="icon icon-shape-burst"></span>
<span class="icon-label">[[__("tool_burst")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('star',$event)">
<span class="icon icon-shape-star"></span>
<span class="icon-label">[[__("tool_star")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="add_shape('heart',$event)">
<span class="icon icon-shape-heart"></span>
<span class="icon-label">[[__("tool_heart")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_arrow()">
<span class="icon icon-tool-arrow"></span>
<span class="icon-label">[[__("tool_arrow")]]</span>
</button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_line()">
<span class="icon icon-tool-line"></span>
<span class="icon-label">[[__("tool_line")]]</span>
</button>
</div> </div>
</div> </div>
<!--
<div class="dialog-section no-p">
<div class="btn-cluster">
<button class="btn btn-transparent text-center"> Upload </button>
<button class="btn btn-transparent text-center" v-on:click="start_drawing_scribble()"> Draw </button>
</div>
</div>
-->

View File

@ -24,6 +24,6 @@
<!--button class="btn btn-transparent btn-icon-labeled" v-on:click="apply_formatting($event,'insertUnorderedList')"> <!--button class="btn btn-transparent btn-icon-labeled" v-on:click="apply_formatting($event,'insertUnorderedList')">
<span class="icon icon-text-list-bullet"></span> <span class="icon icon-text-list-bullet"></span>
<span class="icon-label">Bullets</span> <span class="icon-label">Bullets</span>
</button--!> </button-->
</div> </div>
</div> </div>

View File

@ -1,24 +1,21 @@
<div class="toolbar toolbar-elements" v-bind:class="{in:toolbar_artifacts_in,out:!toolbar_artifacts_in}" v-show="!is_active_space_role('viewer') && active_space_loaded"> <div class="toolbar toolbar-elements" v-bind:class="{in:toolbar_artifacts_in,out:!toolbar_artifacts_in}" v-show="!is_active_space_role('viewer') && active_space_loaded" v-bind:style="{left:toolbar_artifacts_x,top:toolbar_artifacts_y}">
<div class="btn-group light vertical">
<a class="btn btn-icon btn-transparent"
title="[[__("home")]]" href="/spaces"
v-if="(!active_space.parent_space_id && !guest_nickname)">
<span class="icon icon-folder"></span>
</a>
<a class="btn btn-icon btn-dark"
title="Parent Folder"
href="/folders/{{active_space.parent_space_id}}"
v-if="(active_space.parent_space_id && !guest_nickname)">
<span class="icon icon-sd6 icon-svg"></span>
</a>
<button class="btn btn-divider"></button> <div class="btn-group dark">
<div class="dropdown top left light" v-bind:class="{open:opened_dialog=='shapes'}"> <!--div id="search-dialog" class="dropdown bottom light center static" v-bind:class="{open:opened_dialog=='search'}">
<div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='search'}" v-on:click="open_dialog('search')" >
<span class="icon icon-search"></span>
<span class="icon-label">[[__("tool_search")]]</span>
</button>
</div>
<div class="dialog dialog-search">
xinclude "./search.html"
</div>
</div-->
<div class="dropdown bottom light center" v-bind:class="{open:opened_dialog=='shapes'}">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='shapes'}" v-on:click="open_dialog('shapes')"> <button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='shapes'}" v-on:click="open_dialog('shapes')">
<span class="icon icon-shapes"></span> <span class="icon icon-shapes"></span>
@ -31,35 +28,30 @@
</div> </div>
</div> </div>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_scribble()" v-bind:class="{active:active_tool=='scribble'}"> <button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_scribble()">
<span class="icon icon-tool-scribble"></span> <span class="icon icon-tool-scribble"></span>
<span class="icon-label">[[__("tool_scribble")]]</span> <span class="icon-label">[[__("tool_scribble")]]</span>
</button> </button>
<button class="btn btn-icon-labeled btn-transparent" v-on:click="start_drawing_arrow()" v-bind:class="{active:active_tool=='arrow'}">
<span class="icon icon-tool-arrow"></span>
<span class="icon-label">[[__("tool_arrow")]]</span>
</button>
<div class="dropdown bottom light center"> <div class="dropdown bottom light center">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="handle_insert_image_url()" v-on:touchstart="handle_insert_image_url()"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="handle_insert_image_url()" v-on:touchstart="handle_insert_image_url()">
<span class="icon icon-upload"></span> <span class="icon icon-upload"></span>
<span class="icon-label" >Media</span> <span class="icon-label" >[[__("tool_upload")]]</span>
</button> </button>
</div> </div>
</div> </div>
<div class="dropdown bottom light center"> <div class="dropdown bottom light center">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="active_tool='note'" v-bind:class="{active:active_tool=='note'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click=" add_artifact(active_space, 'text', null, $event)">
<span class="icon icon-tool-text"></span> <span class="icon icon-tool-text"></span>
<span class="icon-label">[[__("tool_text")]]</span> <span class="icon-label">[[__("tool_text")]]</span>
</button> </button>
</div> </div>
</div> </div>
<div class="dropdown top left light"> <div class="dropdown bottom light center">
<div class="btn-collapse"> <div class="btn-collapse">
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='image'}" v-on:click="open_dialog('image')"> <button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='image'}" v-on:click="open_dialog('image')">
<span class="icon icon-picture"></span> <span class="icon icon-picture"></span>
@ -72,7 +64,7 @@
</div> </div>
</div> </div>
<div class="dropdown top left light" v-bind:class="{open:opened_dialog=='zones'}"> <div class="dropdown bottom light center" v-bind:class="{open:opened_dialog=='zones'}">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='zones'}" v-on:click="open_dialog('zones')"> <button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='zones'}" v-on:click="open_dialog('zones')">
<span class="icon icon-zone"></span> <span class="icon icon-zone"></span>
@ -87,7 +79,7 @@
<button class="btn btn-divider" v-show="logged_in"></button> <button class="btn btn-divider" v-show="logged_in"></button>
<div class="dropdown top left center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}"> <div class="dropdown bottom light center" v-show="logged_in" v-bind:class="{open:opened_dialog=='background'}">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='background'}" v-on:click="open_dialog('background')"> <button class="btn btn-transparent btn-icon-labeled" v-bind:class="{open:opened_dialog=='background'}" v-on:click="open_dialog('background')">
<span class="letter">bg</span> <span class="letter">bg</span>
@ -100,25 +92,6 @@
</div> </div>
</div> </div>
<button class="btn btn-transparent btn-icon-labeled"
v-if="active_space_role=='admin'"
v-on:click="activate_access()">
<span class="icon icon-share"></span>
<span class="icon-label">[[ __('share') ]]</span>
</button>
<!--
<li v-on:click="edit_space_title()" v-if="logged_in">
<span>
<span class="icon icon-sm icon-tag"></span>
<span>[[ __('rename') ]]</span>
</span>
</li>
-->
<button class="btn btn-transparent btn-icon-labeled" title="Start Presentation (others follow what you see)" v-on:click="toggle_present_mode()" v-bind:class="{open:present_mode}">
<span class="icon icon-presentation"></span>
<span class="icon-label">[[ __('present') ]]</span>
</button>
</div> </div>
</div> </div>

View File

@ -1,38 +1,42 @@
<div class="toolbar toolbar-properties" v-cloak v-show="active_space_loaded && !is_active_space_role('viewer')" v-bind:class="{in:toolbar_props_in,out:!toolbar_props_in}" v-if="active_space_loaded"> <div class="toolbar toolbar-properties" v-cloak v-show="active_space_loaded && !is_active_space_role('viewer')" v-bind:class="{in:toolbar_props_in,out:!toolbar_props_in}" v-bind:style="{left:toolbar_props_x,top:toolbar_props_y}" v-if="active_space_loaded">
<div class="btn-group light vertical"> <div class="btn-group dark">
<div class="dropdown top right light" <div class="dropdown topleft light"
v-bind:class="{open : opened_dialog.match('color') , v-bind:class="{open : opened_dialog.match('color') ,
'option-1':opened_dialog=='color-fill' , 'option-1':opened_dialog=='color-fill' ,
'option-2':opened_dialog=='color-stroke' , 'option-2':opened_dialog=='color-stroke' ,
'option-3':opened_dialog=='color-text', 'option-3':opened_dialog=='color-text',
'options-3':selection_metrics.contains_text}"> 'options-3':selection_metrics.contains_text}">
<button <label
class="dropdown-toggle btn btn-icon btn-transparent" class="dropdown-toggle btn btn-icon btn-transparent no-r-r"
v-on:click="open_dialog('color-fill')" v-on:click="open_dialog('color-fill')"
v-bind:class="{open:opened_dialog=='color-fill'}"> v-bind:class="{open:opened_dialog=='color-fill'}">
<span class="icon icon-tool-fill icon-sm"></span> <span class="icon icon-tool-fill icon-sm"></span>
<span class="jewel" v-bind:style="{'background-color':active_style.fill_color}"></span> <span class="jewel" v-bind:style="{'background-color':active_style.fill_color}"></span>
</button><br> </label>
<button <label
class="dropdown-toggle btn btn-icon btn-transparent" class="dropdown-toggle btn btn-icon btn-transparent no-r"
v-bind:class="{open:opened_dialog=='color-stroke'}" v-bind:class="{open:opened_dialog=='color-stroke'}"
v-on:click="open_dialog('color-stroke')"> v-on:click="open_dialog('color-stroke')">
<span class="icon icon-tool-stroke icon-sm"></span> <span class="icon icon-tool-stroke icon-sm"></span>
<span class="jewel jewel-stroke" v-bind:style="{'border-color':active_style.stroke_color}"></span> <span class="jewel jewel-stroke" v-bind:style="{'border-color':active_style.stroke_color}"></span>
</button><br> </label>
<button <label
class="dropdown-toggle btn btn-icon btn-transparent" class="dropdown-toggle btn btn-icon btn-transparent no-r-l"
v-on:click="open_dialog('color-text')" v-on:click="open_dialog('color-text')"
v-bind:class="{open:opened_dialog=='color-text'}"> v-bind:class="{open:opened_dialog=='color-text'}">
<span class="icon icon-tool-text icon-sm"></span> <span class="icon icon-tool-text icon-sm"></span>
<span class="jewel" v-bind:style="{'border-color':active_style.text_color}">{{active_style.font_size}}</span> <span class="jewel" v-bind:style="{'border-color':active_style.text_color}">{{active_style.font_size}}</span>
</button> </label>
<div class="dialog"> <div class="dialog">
{% include "./color.html" %} {% include "./color.html" %}
</div> </div>
</div> </div>
</div>
<div class="btn-group dark">
<!-- <button class="btn btn-transparent btn-icon-labeled"> <!-- <button class="btn btn-transparent btn-icon-labeled">
<span class="icon icon-tool-eyedrop"></span> <span class="icon icon-tool-eyedrop"></span>
<span class="icon-label">Eyedrop</span> <span class="icon-label">Eyedrop</span>
@ -41,11 +45,11 @@
<button class="btn btn-divider"></button> <button class="btn btn-divider"></button>
--> -->
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-styles'}"> <div class="dropdown top light center" v-bind:class="{open:opened_dialog=='text-styles'}">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-styles')" v-bind:class="{open : opened_dialog=='text-styles'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-styles')" v-bind:class="{open : opened_dialog=='text-styles'}">
<span class="icon icon-text-styles"></span> <span class="icon icon-text-styles"></span>
<span class="icon-label">Styles</span> <span class="icon-label">styles</span>
</button> </button>
</div> </div>
@ -54,7 +58,21 @@
</div> </div>
</div> </div>
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='type-align'}"> <div class="dropdown top light center" v-bind:class="{open:opened_dialog=='filter'}">
<div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_images}">
<!-- <div class="btn-collapse" v-bind:class="in:selection_metrics.count>0"> -->
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('filter')" v-bind:class="{open : opened_dialog=='filter'}">
<span class="icon icon-contrast"></span>
<span class="icon-label">[[__("tool_filter")]]</span>
</button>
</div>
<div class="dialog">
{% include "./filter.html" %}
</div>
</div>
<div class="dropdown top light center" v-bind:class="{open:opened_dialog=='type-align'}">
<div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_text}"> <div class="btn-collapse" v-bind:class="{in:selection_metrics.contains_text}">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('type-align')" v-bind:class="{open : opened_dialog=='type-align'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('type-align')" v-bind:class="{open : opened_dialog=='type-align'}">
<span class="icon icon-text-align-left-alt"></span> <span class="icon icon-text-align-left-alt"></span>
@ -67,9 +85,9 @@
</div> </div>
</div> </div>
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='layout'}"> <div class="dropdown top light center" v-bind:class="{open:opened_dialog=='layout'}">
<div class="btn-collapse in"> <div class="btn-collapse" v-bind:class="{in:selection_metrics.count>0}">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('layout')" v-bind:class="{open : opened_dialog=='layout'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('layout')" v-bind:class="{open : opened_dialog=='layout'}">
<span class="icon icon-cluster"></span> <span class="icon icon-cluster"></span>
<span class="icon-label">[[__("tool_layout")]]</span> <span class="icon-label">[[__("tool_layout")]]</span>
@ -81,13 +99,13 @@
</div> </div>
</div> </div>
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='text-settings'}"> <div class="dropdown top light center" v-bind:class="{open:opened_dialog=='text-settings'}">
<div class="btn-collapse in"> <div class="btn-collapse in">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-settings')" v-bind:class="{open : opened_dialog=='text-settings'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('text-settings')" v-bind:class="{open : opened_dialog=='text-settings'}">
<span class="icon icon-text-typeface"></span> <span class="icon icon-text-typeface"></span>
<span class="icon-label">Font</span> <span class="icon-label">Font</span>
</button> </button>
</div> </div>
<div class="dialog"> <div class="dialog">
@ -97,7 +115,7 @@
<button class="btn btn-divider"></button> <button class="btn btn-divider"></button>
<div class="dropdown top light right" v-bind:class="{open:opened_dialog=='object-options'}"> <div class="dropdown top light center" v-bind:class="{open:opened_dialog=='object-options'}">
<button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('object-options')" v-bind:class="{open : opened_dialog=='object-options'}"> <button class="btn btn-transparent btn-icon-labeled" v-on:click="open_dialog('object-options')" v-bind:class="{open : opened_dialog=='object-options'}">
<span class="icon icon-cogwheel"></span> <span class="icon icon-cogwheel"></span>
<span class="icon-label">[[__("more")]]</span> <span class="icon-label">[[__("more")]]</span>

View File

@ -2,11 +2,11 @@
<div id="zones" style="max-height:500px;overflow-y:scroll"> <div id="zones" style="max-height:500px;overflow-y:scroll">
<div class="dialog-section"> <div class="dialog-section">
<!--p v-if="zones.length<2"> <p v-if="zones.length<2">
Turn your Space into a zooming presentation by placing some Zones and switch through them when presenting. Turn your Space into a zooming presentation by placing some Zones and switch through them when presenting.
</p--> </p>
<button v-on:click="add_zone()" class="btn btn-sm btn-dark">[[__("add_zone")]]</button> <button v-on:click="add_zone()" class="btn btn-sm btn-primary">[[__("add_zone")]]</button>
</div> </div>
<div class="dialog-section no-p" v-for="z in zones | orderBy 'order'" style="white-space: nowrap;text-align:left;cursor:pointer" v-on:click="zoom_to_zone(z)"> <div class="dialog-section no-p" v-for="z in zones | orderBy 'order'" style="white-space: nowrap;text-align:left;cursor:pointer" v-on:click="zoom_to_zone(z)">

View File

@ -9,10 +9,13 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link href="[[ '/images/favicon.png' | cdn ]]" rel="icon" type="image/x-icon" /> <link href="[[ '/images/favicon.png' | cdn ]]" rel="icon" type="image/x-icon" />
<link href='https://fonts.googleapis.com/css?family=Inter' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,700,600,800,300|Montserrat:400,700|EB+Garamond|Vollkorn|Lato|Roboto|Source+Code+Pro|Ubuntu|Raleway|Playfair+Display|Crimson+Text' rel='stylesheet' type='text/css'>
<link type="text/css" rel="stylesheet" href="https://fast.fonts.net/cssapi/ee1a3484-4d98-4f9f-9f55-020a7b37f3c5.css"/>
<link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]"> <link rel="stylesheet" href="[[ '/stylesheets/style.css' | cdn ]]">
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script> <script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twemoji/1.3.2/twemoji.min.js"></script>
<script> <script>
window.socket_auth = '[[socket_auth]]'; window.socket_auth = '[[socket_auth]]';
@ -28,45 +31,53 @@
}; };
</script> </script>
<script src="/javascripts/jquery-2.1.4.min.js"></script> {% if process.env.NODE_ENV == "production" %}
<script src="/javascripts/i18next-1.11.2.js"></script> <script src="[[ '/javascripts/spacedeck.js' | cdn ]]"></script>
<script src="/javascripts/clipboard.js"></script> {% else %}
<script minify src="/javascripts/jquery-2.1.4.min.js"></script>
<script minify src="/javascripts/i18next-1.11.2.js"></script>
<script minify src="/javascripts/clipboard.js"></script>
<script src="/javascripts/lodash.compat.js"></script> <script minify src="/javascripts/lodash.compat.js"></script>
<script src="/javascripts/fastclick.js"></script> <script minify src="/javascripts/fastclick.js"></script>
<script src="/javascripts/vue.js"></script> <script minify src="/javascripts/vue.js"></script>
<script src="/javascripts/moment.js"></script> <script minify src="/javascripts/moment.js"></script>
<script src="/javascripts/medium.patched.js"></script> <script minify src="/javascripts/medium.patched.js"></script>
<script src="/javascripts/route-recognizer.js"></script> <script minify src="/javascripts/route-recognizer.js"></script>
<script src="/javascripts/backend.js"></script> <script minify src="/javascripts/backend.js"></script>
<script src="/javascripts/link_parser.js"></script> <script minify src="/javascripts/link_parser.js"></script>
<script src="/javascripts/vector-render.js"></script> <script minify src="/javascripts/vector-render.js"></script>
<script src="/javascripts/mousetrap.js"></script> <script minify src="/javascripts/mousetrap.js"></script>
<script src="/javascripts/smoke.js"></script> <script minify src="/javascripts/smoke.js"></script>
<script src="/javascripts/helper.js"></script> <script minify src="/javascripts/helper.js"></script>
<script src="/javascripts/packer.growing.js"></script> <script minify src="/javascripts/packer.growing.js"></script>
<script src="/javascripts/spacedeck_routes.js"></script> <script minify src="/javascripts/spacedeck_routes.js"></script>
<script src="/javascripts/spacedeck_formatting.js"></script> <script minify src="/javascripts/spacedeck_formatting.js"></script>
<script src="/javascripts/spacedeck_sections.js"></script> <script minify src="/javascripts/spacedeck_sections.js"></script>
<script src="/javascripts/spacedeck_spaces.js"></script> <script minify src="/javascripts/spacedeck_spaces.js"></script>
<script src="/javascripts/spacedeck_teams.js"></script> <script minify src="/javascripts/spacedeck_teams.js"></script>
<script src="/javascripts/spacedeck_board_artifacts.js"></script> <script minify src="/javascripts/spacedeck_board_artifacts.js"></script>
<script src="/javascripts/spacedeck_users.js"></script> <script minify src="/javascripts/spacedeck_users.js"></script>
<script src="/javascripts/spacedeck_account.js"></script> <script minify src="/javascripts/spacedeck_account.js"></script>
<script src="/javascripts/spacedeck_modals.js"></script> <script minify src="/javascripts/spacedeck_modals.js"></script>
<script src="/javascripts/spacedeck_avatars.js"></script> <script minify src="/javascripts/spacedeck_avatars.js"></script>
<script src="/javascripts/spacedeck_websockets.js"></script> <script minify src="/javascripts/spacedeck_websockets.js"></script>
<script src="/javascripts/spacedeck_whiteboard.js"></script> <script minify src="/javascripts/spacedeck_whiteboard.js"></script>
<script src="/javascripts/spacedeck_directives.js"></script> <script minify src="/javascripts/spacedeck_directives.js"></script>
<script src="/javascripts/spacedeck_vue.js"></script> <script minify src="/javascripts/spacedeck_vue.js"></script>
{% endif %}
<script>if (window.module) module = window.module;</script> <script>if (window.module) module = window.module;</script>
</head> </head>
<body id="main" v-bind:class="{'present-mode':present_mode,'modal-open':active_modal}" v-on:click="handle_body_click($event)"> <body id="main" v-bind:class="{'present-mode':present_mode,'modal-open':active_modal}" v-on:click="handle_body_click($event)">
<!--[if lt IE 10]>
<p class="browsehappy">You are using an <strong>outdated</strong> version of Internet Explorer. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
{% include "./partials/login.html" %} {% include "./partials/login.html" %}
{% include "./partials/space.html" %} {% include "./partials/space.html" %}
{% include "./partials/folders.html" %} {% include "./partials/folders.html" %}
@ -77,6 +88,10 @@
{% include "./partials/modal/access.html" %} {% include "./partials/modal/access.html" %}
{% include "./partials/modal/folder-settings.html" %} {% include "./partials/modal/folder-settings.html" %}
{% include "./partials/modal/support.html" %}
{% include "./partials/modal/login.html" %}
{% include "./partials/modal/pdfoptions.html" %}
</body> </body>
<script type="text/javascript"> <script type="text/javascript">