3 Commits

Author SHA1 Message Date
Lukas F. Hartmann
386d784952 touch: fix vector transforming (points of arrows, scribbles) 2020-12-18 18:11:33 +01:00
Lukas F. Hartmann
352b01569f touch: fix media upload on iDevice 2020-12-18 17:36:44 +01:00
Lukas F. Hartmann
82515e3a8e touch (tablet): fix deselect when tapping space; add edit text button 2020-12-18 17:07:32 +01:00
28 changed files with 16396 additions and 7961 deletions

3
.gitignore vendored
View File

@@ -5,5 +5,4 @@ public/stylesheets/*.css
database.sqlite
*.swp
*~
storage/
.DS_Store

View File

@@ -1 +0,0 @@
nodejs 10.23.1

14
.vscode/launch.json vendored
View File

@@ -1,14 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Nodemon",
"runtimeExecutable": "${workspaceFolder}/node_modules/nodemon/bin/nodemon.js",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/spacedeck.js",
"cwd": "${workspaceFolder}"
}
]
}

View File

@@ -21,20 +21,6 @@ RUN cd audiowaveform/build/ && cmake -D ENABLE_TESTS=0 -D BUILD_STATIC=1 ..
RUN cd audiowaveform/build/ && make
RUN cd audiowaveform/build/ && make install
# install chromium
RUN apk add --no-cache \
chromium \
nss \
freetype \
freetype-dev \
harfbuzz \
ca-certificates \
ttf-freefont
# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
# install other requirements
RUN apk add graphicsmagick ffmpeg ffmpeg-dev ghostscript

View File

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

View File

@@ -45,52 +45,6 @@ To install all node dependencies, run (do this once):
See [config/default.json](config/default.json). Set `storage_local_path` for a local sqlite database or `storage_region`, `storage_bucket`, `storage_cdn` and `storage_endpoint` for AWS S3. `mail_provider` may be one of `console` or `smtp`. Also, omit a trailing `/` for the `endpoint`.
## Disable DB logs
```json
...
"db_logs_disabled": true
...
```
## Configure color swatches
Add a custom array of swatches to your config/default.json.
**You should include the swatch transparent (rgba(0,0,0,0)) so users can remove the color applied.**
## Configure default colors
You can define text, stroke and fill color in your config/default.json.
**You also should include the default colors in your custom swatches palette.**
```json
...
"spacedeck": {
"default_text_color": "#E11F26",
"default_stroke_color": "#9E0F13",
"default_fill_color": "#64BCCA",
"swatches": [
{"id":8, "hex":"#000000"},
{"id":30, "hex":"rgba(0,0,0,0)"},
{"id":31, "hex": "#E11F26"},
{"id":32, "hex": "#9E0F13"},
{"id":33, "hex": "#64BCCA"},
{"id":34, "hex": "#40808A"},
{"id":35, "hex": "#036492"},
{"id":36, "hex": "#005179"},
{"id":37, "hex": "#84427E"},
{"id":38, "hex": "#6C3468"},
{"id":39, "hex": "#F79B84"},
{"id":40, "hex": "#B57362"},
{"id":41, "hex": "#E7D45A"},
{"id":42, "hex": "#ACA044"}
]
}
...
```
# Run (web server)
node spacedeck.js
@@ -110,26 +64,6 @@ For advanced media conversion:
By default, media files are uploaded to the ```storage``` folder.
The database is stored in ```database.sqlite``` by default.
# Other databases (Not officially supported)
## Postgres
Add the [pg](https://www.npmjs.com/package/pg) module and change the config/default.json to
```
"storage_dialect": "postgres",
```
Adapt the other values as needed
```
"storage_host": "localhost",
"storage_database": "spacedeck",
"storage_username": "username",
"storage_password": "password",
```
# Run with Docker
- configure `config/default.json`

View File

@@ -7,13 +7,6 @@
"endpoint": "http://localhost:9666",
"invite_code": "top-sekrit",
"storage_dialect": "sqlite",
"storage_host": "localhost",
"storage_database": "spacedeck",
"storage_username": "username",
"storage_password": "password",
"storage_local_path": "./storage",
"storage_local_db": "./database.sqlite",
"storage_region": "eu-central-1",
@@ -25,7 +18,7 @@
"redis_mock": true,
"redis_host": "localhost",
"export_api_secret": "very_secret_export_password",
"phantom_api_secret": "very_secret_phantom_password",
"mail_provider": "smtp",
"mail_smtp_host": "your.smtp.host",
@@ -33,6 +26,5 @@
"mail_smtp_secure": true,
"mail_smtp_require_tls": true,
"mail_smtp_user": "your.smtp.user",
"mail_smtp_pass": "your.secret.smtp.password",
"spacedeck": {}
"mail_smtp_pass": "your.secret.smtp.password"
}

View File

@@ -50,8 +50,6 @@ const convertableAudioTypes = [
"audio/x-hx-aac-adts",
"audio/aac"];
// ffmpeg progress
var duration = 0, time = 0, progress = 0;
function getDuration(localFilePath, callback){
exec.execFile("ffprobe", ["-show_format", "-of", "json", localFilePath], function(error, stdout, stderr) {
@@ -60,40 +58,6 @@ function getDuration(localFilePath, callback){
});
}
function getConversionProgress(content){
// get duration of source
var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
if( matches && matches.length>0 ){
var rawDuration = matches[1];
// convert rawDuration from 00:00:00.00 to seconds.
var ar = rawDuration.split(":").reverse();
duration = parseFloat(ar[0]);
if (ar[1]) duration += parseInt(ar[1]) * 60;
if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
}
// get the time
matches = content.match(/time=(.*?) bitrate/g);
if( matches && matches.length>0 ){
var rawTime = matches.pop();
// needed if there is more than one match
if (Array.isArray(rawTime)){
rawTime = rawTime.pop().replace('time=','').replace(' bitrate','');
} else {
rawTime = rawTime.replace('time=','').replace(' bitrate','');
}
// convert rawTime from 00:00:00.00 to seconds.
ar = rawTime.split(":").reverse();
time = parseFloat(ar[0]);
if (ar[1]) time += parseInt(ar[1]) * 60;
if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
//calculate the progress
progress = Math.round((time/duration) * 100);
}
return progress;
}
function createWaveform(fileName, localFilePath, callback){
var filePathImage = localFilePath + "-" + (new Date().getTime()) + ".png";
@@ -171,7 +135,7 @@ function convertVideo(fileName, filePath, codec, callback, progressCallback) {
ff.stderr.on('data', function (data) {
console.log('[ffmpeg-video] stderr: ' + data);
if (progressCallback) {
progressCallback(getConversionProgress(""+data)+"%");
progressCallback(data);
}
});

View File

@@ -1,57 +0,0 @@
'use strict';
const db = require('../models/db');
const config = require('config');
const puppeteer = require('puppeteer');
const os = require('os');
module.exports = {
// type = "pdf" or "png"
takeScreenshot: function(space,type,on_success,on_error) {
var spaceId = space._id;
var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html";
var export_path = os.tmpdir()+"/"+spaceId+"."+type;
var timeout = 5000;
if (type=="pdf") timeout = 30000;
space_url += "?api_token="+config.get("export_api_secret");
console.log("[space-screenshot] url: "+space_url);
console.log("[space-screenshot] export_path: "+export_path);
(async () => {
let browser;
let page;
try {
browser = await puppeteer.launch(
{
headless: true,
args: ['--disable-dev-shm-usage', '--no-sandbox']
}
);
page = await browser.newPage();
page.setDefaultTimeout(timeout);
await page.setJavaScriptEnabled(false);
await page.goto(space_url, {waitUntil: 'networkidle2'});
await page.emulateMediaType('screen');
if (type=="pdf") {
await page.pdf({path: export_path, printBackground: true, width: space.width+'px', height: space.height+'px' });
}else{
await page.screenshot({path: export_path, printBackground: true});
}
await browser.close();
on_success(export_path);
} catch (error) {
console.error(error);
console.error("[space-screenshot] puppeteer abnormal exit for url "+space_url);
on_error();
}
})();
}
};

70
helpers/phantom.js Normal file
View File

@@ -0,0 +1,70 @@
'use strict';
const db = require('../models/db');
const config = require('config');
const phantom = require('node-phantom-simple');
const os = require('os');
module.exports = {
// type = "pdf" or "png"
takeScreenshot: function(space,type,on_success,on_error) {
var spaceId = space._id;
var space_url = config.get("endpoint")+"/api/spaces/"+spaceId+"/html";
var export_path = os.tmpdir()+"/"+spaceId+"."+type;
var timeout = 5000;
if (type=="pdf") timeout = 30000;
space_url += "?api_token="+config.get("phantom_api_secret");
console.log("[space-screenshot] url: "+space_url);
console.log("[space-screenshot] export_path: "+export_path);
var on_success_called = false;
var on_exit = function(exit_code) {
if (exit_code>0) {
console.error("phantom abnormal exit for url "+space_url);
if (!on_success_called && on_error) {
on_error();
}
}
};
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
if (err) {
console.error(err);
} else {
return browser.createPage(function (err, page) {
console.log("page created, opening ",space_url);
if (type=="pdf") {
var psz = {
width: space.width+"px",
height: space.height+"px"
};
page.set('paperSize', psz);
}
page.set('settings.resourceTimeout',timeout);
page.set('settings.javascriptEnabled',false);
return page.open(space_url, function (err,status) {
page.render(export_path, function() {
on_success_called = true;
if (on_success) {
on_success(export_path);
}
page.close();
browser.exit();
});
});
});
}
}, {
onExit: on_exit
});
}
};

View File

@@ -320,6 +320,5 @@
"follow_present": "Folgen",
"mute_present": "Entfolgen",
"follow_present_help": "Wenn jemand den Space präsentiert, folgen die anderen Mitglieder automatisch der Präsentation. Mit diesem Knopf lässt sich das an- oder ausschalten.",
"media": "Media",
"tool_edit_text": "Text bearbeiten"
"media": "Media"
}

View File

@@ -173,7 +173,7 @@
"tool_bullets": "Bullets",
"tool_numbers": "Nombres",
"color_fill": "Fill",
"tool_font": "Poliça",
"tool_font": "Font",
"color_stroke": "Traçat",
"color_text": "Tèxte",
"tool_type": "Tipe",
@@ -253,7 +253,7 @@
"access_anonymous_edit_blocking": "Los convidats pòdon pas modificar los elements quan creats.",
"access_current_members": "Membres actuals",
"access_new_members": "Convidar de novèls membres",
"access_no_members": "Los membres daqueste Espaci apareisseràn aquí.",
"access_no_members": "Los membres daqueste Espacii apreissaràn aquí.",
"comments": "comentaris",
"landing_customers": "La fisança de milièr de personas.",
"landing_features_title": "Un jòc d'enfants dutilizar.",
@@ -309,7 +309,7 @@
"list": "lista",
"link": "Ligam",
"download_space": "Telecargar espaci",
"download_space_as_pdf": "Telecargar espaci coma PDF",
"download_space_as_pdf": "Telecargar espaci PDF",
"type": "Tipe",
"download": "Telecargar",
"Previous Zone": "Zòna precedenta",
@@ -321,7 +321,7 @@
"unlock": "Desverrolhar",
"follow_present": "Seguir",
"mute_present": "Quitar de seguir",
"follow_present_help": "Se qualquun mai presenta aqueste espaci, los demai membres seguiràn automaticament la presentacion. Basculatz labonament a la presentacion amb aqueste boton.",
"follow_present_help": "follow_present_help",
"export": "exportar",
"media": "Mèdia"
"media": "Media"
}

View File

@@ -86,7 +86,7 @@ module.exports = (req, res, next) => {
// space is private
// special permission for screenshot/pdf export from backend
if (req.query['api_token'] && req.query['api_token'] == config.get('export_api_secret')) {
if (req.query['api_token'] && req.query['api_token'] == config.get('phantom_api_secret')) {
finalizeReq(space, "viewer");
return;
}

View File

@@ -6,28 +6,24 @@ function sequel_log(a,b,c) {
}
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
config.get('storage_database'),
config.get('storage_username'),
config.get('storage_password'),
{
host: config.get('storage_host'),
dialect: config.get('storage_dialect'),
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'sqlite',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
logging: config.has('db_logs_disabled') ? false : sequel_log,
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
operatorsAliases: false,
// SQLite only
storage: config.get('storage_local_db')
}
);
// https://github.com/sequelize/sequelize/issues/8019#issuecomment-384316346
Sequelize.postgres.DECIMAL.parse = function (value) { return parseFloat(value); };
storage: config.get('storage_local_db'),
logging: sequel_log,
// http://docs.sequelizejs.com/manual/tutorial/querying.html#operators
operatorsAliases: false
});
var User;
var Session;

7466
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node spacedeck.js",
"dev": "nodemon spacedeck.js",
"styles": "gulp styles"
"start": "node spacedeck.js"
},
"engines": {
"node": ">=10.0.0"
@@ -24,14 +22,19 @@
"file-type": "^7.6.0",
"glob": "7.1.1",
"gm": "^1.23.1",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-sass": "^4.0.2",
"helmet": "^3.5.0",
"i18n-2": "0.6.3",
"log-timestamp": "latest",
"mock-aws-s3": "^2.6.0",
"moment": "^2.19.3",
"morgan": "^1.9.1",
"node-phantom-simple": "2.2.4",
"node-server-screenshot": "^0.2.1",
"nodemailer": "^4.6.7",
"puppeteer": "8.0.0",
"phantomjs-prebuilt": "^2.1.16",
"read-chunk": "^2.1.0",
"request": "^2.88.0",
"sanitize-html": "^1.11.1",
@@ -46,13 +49,6 @@
"validator": "7.0.0",
"ws": "3.3.1"
},
"devDependencies": {
"gulp": "^4.0.2",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-sass": "^4.0.2",
"nodemon": "^2.0.6"
},
"main": "app.js",
"description": "",
"directories": {},

View File

@@ -68,9 +68,9 @@ var SpacedeckSections = {
line_height: 1.5,
letter_spacing: 0,
stroke_color: ENV.options.default_stroke_color ? ENV.options.default_stroke_color : "#000000",
fill_color: ENV.options.default_fill_color ? ENV.options.default_fill_color : "#000000",
text_color: ENV.options.default_text_color ? ENV.options.default_text_color : "#000000",
stroke_color: "#000000",
fill_color: "#00000000",
text_color: "#000000",
background_color: "#ffffff",
padding: 0,
@@ -109,7 +109,7 @@ var SpacedeckSections = {
color_picker_hue: 127,
color_picker_opacity: 255,
swatches: ENV.options.swatches ? ENV.options.swatches : [
swatches: [
{id:1, hex:"#ff00ff"},
{id:2, hex:"#ffff00"},
{id:3, hex:"#00ffff"},
@@ -133,7 +133,18 @@ var SpacedeckSections = {
{id:26, hex:"#d55c4b"},
{id:27, hex:"#6f4021"},
{id:29, hex:"#95a5a6"},
{id:30, hex:"rgba(0,0,0,0)"}
{id:30, hex:"rgba(0,0,0,0)"},
],
swatches_text: [
{id:1, hex:"#9b59b6"},
{id:2, hex:"#3498db"},
{id:3, hex:"#2ecc71"},
{id:4, hex:"#f1c40f"},
{id:5, hex:"#e67e22"},
{id:6, hex:"#d55c4b"},
{id:8, hex:"#ffffff"},
{id:10, hex:"#252525"},
],
fonts: [

View File

@@ -23,9 +23,6 @@ function vec2_angle(v) {
function render_vector_drawing(a, padding) {
var shape = a.shape || "";
var path = [];
if(typeof a.control_points == 'string'){
a.control_points = JSON.parse(a.control_points);
}
var p = a.control_points[0];
if (!p) return "";

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@ const db = require('../../models/db');
var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
var space_render = require('../../helpers/space-render');
var exporter = require('../../helpers/exporter');
var phantom = require('../../helpers/phantom');
var async = require('async');
var moment = require('moment');
@@ -51,7 +51,7 @@ router.get('/png', function(req, res, next) {
if (!req.space.thumbnail_updated_at || req.space.thumbnail_updated_at < req.space.updated_at || !req.space.thumbnail_url) {
db.Space.update({ thumbnail_updated_at: triggered }, {where : {"_id": req.space._id }});
exporter.takeScreenshot(req.space, "png", function(local_path) {
phantom.takeScreenshot(req.space, "png", function(local_path) {
var localResizedFilePath = local_path + ".thumb.jpg";
gm(local_path).resize(640, 480).quality(70.0).autoOrient().write(localResizedFilePath, function(err) {
@@ -109,7 +109,7 @@ function make_export_filename(space, extension) {
router.get('/pdf', function(req, res, next) {
var s3_filename = make_export_filename(req.space, "pdf");
exporter.takeScreenshot(req.space, "pdf", function(local_path) {
phantom.takeScreenshot(req.space, "pdf", function(local_path) {
uploader.uploadFile(s3_filename, "application/pdf", local_path, function(err, url) {
res.status(201).json({
url: url

View File

@@ -9,7 +9,7 @@ var redis = require('../../helpers/redis');
var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
var space_render = require('../../helpers/space-render');
var exporter = require('../../helpers/exporter');
var phantom = require('../../helpers/phantom');
var async = require('async');
var fs = require('fs');

View File

@@ -10,7 +10,7 @@ var redis = require('../../helpers/redis');
var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
var space_render = require('../../helpers/space-render');
var exporter = require('../../helpers/exporter');
var phantom = require('../../helpers/phantom');
var payloadConverter = require('../../helpers/artifact_converter');
var slug = require('slug');

View File

@@ -1,10 +1,10 @@
"use strict";
const puppeteer = require('puppeteer');
var config = require('config');
require('../../models/db');
var fs = require('fs');
var phantom = require('node-phantom-simple');
var md5 = require('md5');
var express = require('express');
@@ -19,39 +19,40 @@ function website_to_png(url,on_success,on_error) {
console.log("[webgrabber] url: "+url);
console.log("[webgrabber] export_path: "+export_path);
var on_success_called = false;
var on_exit = function(exit_code) {
if (exit_code>0) {
console.log("[phantom-webgrabber] abnormal exit for url "+url);
if (!on_success_called && on_error) {
on_error();
}
}
};
fs.stat(export_path, function(err, stat) {
if (!err) {
// file exists
console.log("[webgrabber] serving cached snapshot of url: "+url);
on_success(export_path);
} else {
(async () => {
let browser;
let page;
try {
browser = await puppeteer.launch(
{
headless: true,
args: ['--disable-dev-shm-usage', '--no-sandbox']
}
);
page = await browser.newPage();
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
return browser.createPage(function (err, page) {
page.set('settings.resourceTimeout',timeout);
page.set('settings.javascriptEnabled',false);
page.setDefaultTimeout(timeout);
await page.setJavaScriptEnabled(false);
await page.goto(url, {waitUntil: 'networkidle2'});
await page.emulateMedia('screen');
await page.screenshot({path: export_path, printBackground: true});
await browser.close();
return page.open(url, function(err, status) {
console.log("[webgrabber] status: "+status);
page.render(export_path, function() {
on_success_called = true;
on_success(export_path);
} catch (error) {
console.error(error);
console.log("[webgrabber] puppeteer abnormal exit for url "+url);
on_error();
}
})();
browser.exit();
});
});
});
}, {
onExit: on_exit
});
}
});
}

View File

@@ -11,9 +11,7 @@
max-height: 100%;
}
&.hide-text .text {
opacity: 0;
}
&.hide-text .text { opacity: 0 }
&.locked.selected {
box-shadow: 0px 0px 0px 3px rgba(0,0,0,0.5) !important;
@@ -28,9 +26,7 @@
}
}
&.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";
opacity: 0.25;
}
@@ -83,6 +79,7 @@
// padding-right: 20px; margin-right: -20px;
//> * {pointer-events: auto; }
}
&:not(.artifact-text) {
@@ -145,9 +142,7 @@
li {
margin-top: 0;
margin-bottom: 0.5em;
&:last-child {
margin-bottom: 0em !important;
}
&:last-child {margin-bottom: 0em !important; }
}
h1 {
@@ -184,14 +179,10 @@
p {
margin-top: 0;
margin-bottom: 0.5em; // compatibility to old system
&:last-child {
margin-bottom: 0em !important;
}
&:last-child {margin-bottom: 0em !important; }
}
a {
pointer-events: none;
}
a {pointer-events: none; }
ol {
padding: 0;
@@ -256,7 +247,7 @@
}
.oembed,
div[class*="oembed-"] {
div[class*='oembed-'] {
height: 100%;
.play {
position: absolute;
@@ -299,9 +290,7 @@
}
}
.title {
font-size: 20px;
}
.title {font-size: 20px; }
.image {
height: auto;
top: 0;
@@ -334,7 +323,6 @@
width: 100%;
height: 100%;
background-size: cover;
background-color: black;
&.playing {
video {
@@ -359,7 +347,6 @@
width: 100%;
height: 100%;
position: absolute;
left: 0;
}
.tl-controls {
@@ -372,8 +359,10 @@
.btn {
margin-top: 20px;
}
}
}
// FIXME: fix later
@@ -438,6 +427,7 @@
.btn {
margin-top: 20px;
}
}
@@ -464,41 +454,19 @@
height: 100%;
}
&.bold {
font-weight: bold;
}
&.italic {
font-style: italic;
}
&.underline {
text-decoration: underline;
}
&.strike {
text-decoration: line-through;
}
&.bold { font-weight: bold;}
&.italic { font-style: italic;}
&.underline { text-decoration: underline;}
&.strike { text-decoration: line-through;}
&.align-top .text-cell {
vertical-align: top;
}
&.align-middle .text-cell {
vertical-align: middle;
}
&.align-bottom .text-cell {
vertical-align: bottom;
}
&.align-top .text-cell {vertical-align: top;}
&.align-middle .text-cell {vertical-align: middle;}
&.align-bottom .text-cell {vertical-align: bottom;}
&.align-left {
text-align: left;
}
&.align-center {
text-align: center;
}
&.align-right {
text-align: right;
}
&.align-justify {
text-align: justify;
}
&.align-left { text-align: left; }
&.align-center { text-align: center; }
&.align-right { text-align: right; }
&.align-justify { text-align: justify; }
audio {
width: 100%;
@@ -515,12 +483,8 @@
&.artifact-zone {
background-color: rgba(0,0,0,0.05);
border-radius: 10px;
&:after {
display: none;
}
.shape {
display: none;
}
&:after {display: none; }
.shape {display: none; }
.zone {
height: 100%;
}
@@ -534,20 +498,21 @@ body.present-mode {
}
.artifact {
cursor: default !important;
.text a {
pointer-events: auto !important;
}
.text a { pointer-events: auto !important; }
}
}
}
body:not(.present-mode) {
#space {
.Medium {
cursor: text;
}
.artifact {
&.selected.text-editing,
&.text-editing {
cursor: text;
@@ -575,22 +540,19 @@ body:not(.present-mode) {
//background-color: rgba(40,140,215,0.35);
}
}
}
}
}
.mouse-scribble,
.tool-scribble,
.tool-line,
.tool-arrow {
.mouse-scribble, .tool-scribble, .tool-line, .tool-arrow {
cursor: crosshair !important;
.artifact {
pointer-events: none !important;
}
.artifact:after,
.artifact:before {
.artifact:after, .artifact:before {
display: none !important;
}
}
@@ -604,27 +566,21 @@ body:not(.present-mode) {
}
.artifact.state-idle {
.progress,
.progress-text {
.progress, .progress-text {
display: none;
}
}
.artifact.state-processing,
.artifact.state-uploading {
.artifact.state-processing, .artifact.state-uploading {
.progress {
height: 100%;
padding: 4px;
padding: 10px;
background-color: $blue;
opacity: 0.9;
text-align: center;
font-size: 14px;
}
.progress-container {
background: $white;
width: 100%;
height: 100%;
padding-left: 10px;
padding-top: 10px;
}
.progress-text {
text-align: center;
padding: 8px;
@@ -637,38 +593,33 @@ body:not(.present-mode) {
color: #888;
font-size: 10px;
}
video,
audio,
.tl-controls,
.timeline {
video, audio, .tl-controls, .timeline {
display: none;
}
background-color: white;
}
.state-processing .spinner {
opacity: 1;
background-image: url("/images/hourglass.gif");
background-image: url('/images/hourglass.gif');
}
.state-uploading .spinner {
opacity: 0.8;
background-image: url("/images/hourglass.gif");
background-image: url('/images/hourglass.gif');
}
.state-idle .spinner {
display: none;
}
.artifact.image {
background-color: transparent;
&.state-loading {
background-color: rgba(40, 140, 215, 0.05);
}
&.state-processing {
background-color: rgba(107, 195, 111, 0.05);
}
&.state-loading { background-color: rgba(40,140,215,0.05);}
&.state-processing { background-color: rgba(107,195,111,0.05);}
}
.spinner {

View File

@@ -3,17 +3,12 @@
@import "unicode";
@-webkit-keyframes appear {
0% {
opacity: 0;
}
30% {
opacity: 0;
}
100% {
opacity: 1;
}
0% { opacity: 0;}
30% { opacity: 0;}
100% { opacity: 1; }
}
.avatar {
background-color: $blue;
font-family: $main-font;
@@ -31,9 +26,7 @@
#user-root {
margin-left: 5px !important;
padding: 0px !important;
.btn {
margin-right: 10px;
}
.btn {margin-right: 10px; }
}
#sidebar.folder-sidebar {
@@ -77,9 +70,7 @@
li {
display: inline-block;
line-height: 44px;
&.active span {
color: $light;
}
&.active span {color: $light; }
span {
color: $medium;
display: inline-block;
@@ -91,6 +82,8 @@
}
}
#folder {
position: absolute;
height: 100%;
@@ -157,7 +150,7 @@
width: 100%;
}
> .icon {
margin-left: -15px;
margin-left: -15px
}
}
@@ -219,22 +212,15 @@
margin: auto;
}
#folder-grid .item {
float: left;
width: 100%;
@media screen and (min-width: 640px) {
width: 50%;
}
@media screen and (min-width: 800px) {
width: 33.333333%;
}
@media screen and (min-width: 1000px) {
width: 25%;
}
@media screen and (min-width: 1200px) {
width: 20%;
}
@media screen and (min-width: 640px) {width: 50%; }
@media screen and (min-width: 800px) {width: 33.333333%; }
@media screen and (min-width: 1000px) {width: 25%; }
@media screen and (min-width: 1200px) {width: 20%; }
}
.compact-hidden {
@@ -279,9 +265,7 @@
cursor: pointer;
.folder-drop {
display: none;
}
.folder-drop {display:none; }
&.appear > a,
&.creating > a {
@@ -365,13 +349,7 @@
background-color: $darker;
position: absolute;
bottom: 2px;
-webkit-mask-image: -webkit-gradient(
linear,
left top,
left bottom,
from(rgba(0, 0, 0, 0)),
to(rgba(0, 0, 0, 0.1))
);
-webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.1)));
background-color: black;
pointer-events: none;
}
@@ -416,9 +394,7 @@
background-color: white;
border-radius: $radius*2;
&:active {
opacity: 0.95 !important;
}
&:active { opacity: 0.95 !important; }
box-shadow: 0 0 30px 1px rgba(0, 0, 0, 0.15);
border: 1px solid black;
@@ -444,7 +420,6 @@
overflow: hidden;
background-color: transparent;
background-size: cover;
border-top-left-radius: $radius*2;
border-top-right-radius: $radius*2;

View File

@@ -2,8 +2,9 @@
<div class="footer">
<p>
<div class="col-xs-6">
Spacedeck is Free and Open Source Software. The developers are not affiliated with this website.<br>
&copy; 20112020 <a href="https://github.com/mntmn/spacedeck-open">Spacedeck Open Developers</a><br>
&copy; 2020 <a href="https://mntre.com">MNT Research GmbH</a>, Fehlerstr. 8, 12161 Berlin, Germany<br>
&copy; 20112020 Spacedeck GmbH (in liquidation)<br>
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>

View File

@@ -156,13 +156,8 @@
<source v-for="rep in a.view.payload_alternatives" v-bind:src="rep.payload_uri" v-bind:type="rep.mime" />
<source v-if="a.view.payload_uri && a.view.mime" v-bind:src="a.view.payload_uri" v-bind:type="a.view.mime" />
</video>
<div class="progress" v-bind:style="{width: a.description}">
<div class="progress-container">
<h3>
{{a.description}}
</h3>
</div>
</div>
<div class="spinner"></div>
<div class="progress" v-bind:style="{width: a.view.progress+'%'}">{{a.description}}</div>
</div>
<!-- audio -->

View File

@@ -17,8 +17,7 @@
webHost: location.host,
webEndpoint: location.origin,
apiEndpoint: location.origin,
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:"),
options: <%- config.spacedeck ? JSON.stringify(config.spacedeck) : "{}" %>
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
};
</script>