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