2020-06-08 16:39:26 +03:00
< template >
2020-08-17 22:29:29 +03:00
< div id = "app-dashboard" :style ="backgroundStyle" >
2020-08-07 16:57:38 +03:00
< h2 > { { greeting . text } } < / h2 >
2020-08-20 01:54:11 +03:00
< ul class = "statuses" >
2020-08-20 11:08:30 +03:00
< div v -for = " status in sortedRegisteredStatus "
2020-08-04 12:58:14 +03:00
: id = "'status-' + status"
2020-08-18 15:11:02 +03:00
: key = "status" >
< div : ref = "'status-' + status" / >
< / div >
2020-08-20 01:54:11 +03:00
< / ul >
2020-06-08 16:39:26 +03:00
2020-08-05 13:39:33 +03:00
< Draggable v -model = " layout "
class = "panels"
handle = ".panel--header"
@ end = "saveLayout" >
2020-07-22 12:29:35 +03:00
< div v-for ="panelId in layout" :key="panels[panelId].id" class="panel" >
2020-06-15 09:18:50 +03:00
< div class = "panel--header" >
2020-08-20 19:07:07 +03:00
< h2 :class ="panels[panelId].iconClass" >
2020-07-22 12:29:35 +03:00
{ { panels [ panelId ] . title } }
2020-08-20 19:07:07 +03:00
< / h2 >
2020-06-15 09:18:50 +03:00
< / div >
2020-08-24 15:24:17 +03:00
< div class = "panel--content" : class = "{ loading: !panels[panelId].mounted }" >
2020-07-10 18:35:18 +03:00
< div :ref ="panels[panelId].id" :data-id ="panels[panelId].id" / >
< / div >
2020-07-22 12:29:35 +03:00
< / div >
< / Draggable >
2020-08-05 09:29:50 +03:00
2020-09-04 09:10:59 +03:00
< div class = "footer" >
< a class = "edit-panels icon-rename"
2020-08-17 02:17:06 +03:00
tabindex = "0"
2020-08-17 21:04:05 +03:00
@ click = "showModal"
@ keyup . enter = "showModal"
@ keyup . space = "showModal" > { { t ( 'dashboard' , 'Customize' ) } } < / a >
2020-08-12 09:10:58 +03:00
< / div >
2020-08-05 09:29:50 +03:00
2020-06-15 09:18:50 +03:00
< Modal v-if ="modal" @close="closeModal" >
< div class = "modal__content" >
2020-07-31 15:51:14 +03:00
< h3 > { { t ( 'dashboard' , 'Edit widgets' ) } } < / h3 >
2020-08-21 16:25:38 +03:00
< ol class = "panels" >
2020-08-21 18:05:10 +03:00
< li v-for ="status in sortedAllStatuses" :key ="status" >
2020-08-21 16:25:38 +03:00
< input : id = "'status-checkbox-' + status"
type = "checkbox"
class = "checkbox"
: checked = "isStatusActive(status)"
@ input = "updateStatusCheckbox(status, $event.target.checked)" >
< label : for = "'status-checkbox-' + status" :class ="statusInfo[status].icon" >
{ { statusInfo [ status ] . text } }
< / label >
< / li >
< / ol >
2020-07-27 12:17:31 +03:00
< Draggable v -model = " layout "
class = "panels"
tag = "ol"
2020-08-05 13:39:33 +03:00
handle = ".draggable"
2020-07-27 12:17:31 +03:00
@ end = "saveLayout" >
2020-06-15 09:18:50 +03:00
< li v-for ="panel in sortedPanels" :key="panel.id" >
< input : id = "'panel-checkbox-' + panel.id"
type = "checkbox"
class = "checkbox"
: checked = "isActive(panel)"
@ input = "updateCheckbox(panel, $event.target.checked)" >
2020-08-05 13:39:33 +03:00
< label : for = "'panel-checkbox-' + panel.id" : class = "isActive(panel) ? 'draggable ' + panel.iconClass : panel.iconClass" >
2020-06-15 09:18:50 +03:00
{ { panel . title } }
< / label >
< / li >
2020-07-27 12:17:31 +03:00
< / Draggable >
2020-08-19 18:04:24 +03:00
< a v-if ="isAdmin" :href="appStoreUrl" class="button" > {{ t ( ' dashboard ' , ' Get more widgets from the app store ' ) }} < / a >
2020-08-11 17:45:02 +03:00
2020-08-17 02:17:06 +03:00
< h3 > { { t ( 'dashboard' , 'Change background image' ) } } < / h3 >
2020-08-19 22:50:40 +03:00
< BackgroundSettings :background ="background" @update:background ="updateBackground" / >
2020-08-20 11:08:30 +03:00
< h3 > { { t ( 'dashboard' , 'Weather service' ) } } < / h3 >
< p >
{ { t ( 'dashboard' , 'For your privacy, the weather data is requested by your Nextcloud server on your behalf so the weather service receives no personal information.' ) } }
< / p >
< p class = "credits--end" >
< a href = "https://api.met.no/doc/TermsOfService" target = "_blank" rel = "noopener" > { { t ( 'dashboard' , 'Weather data from Met.no' ) } } < / a > , < a href = "https://wiki.osmfoundation.org/wiki/Privacy_Policy" target = "_blank" rel = "noopener" > { { t ( 'dashboard' , 'geocoding with Nominatim' ) } } < / a > , < a href = "https://www.opentopodata.org/#public-api" target = "_blank" rel = "noopener" > { { t ( 'dashboard' , 'elevation data from OpenTopoData' ) } } < / a > .
< / p >
2020-06-08 16:39:26 +03:00
< / div >
2020-06-15 09:18:50 +03:00
< / Modal >
2020-06-08 16:39:26 +03:00
< / div >
< / template >
< script >
import Vue from 'vue'
import { loadState } from '@nextcloud/initial-state'
import { getCurrentUser } from '@nextcloud/auth'
2020-06-15 09:18:50 +03:00
import { Modal } from '@nextcloud/vue'
2020-07-22 12:29:35 +03:00
import Draggable from 'vuedraggable'
2020-06-15 09:18:50 +03:00
import axios from '@nextcloud/axios'
2020-08-17 22:29:29 +03:00
import { generateUrl } from '@nextcloud/router'
2020-08-11 08:54:34 +03:00
import isMobile from './mixins/isMobile'
2020-08-12 11:02:33 +03:00
import BackgroundSettings from './components/BackgroundSettings'
2020-08-17 22:29:29 +03:00
import getBackgroundUrl from './helpers/getBackgroundUrl'
import prefixWithBaseUrl from './helpers/prefixWithBaseUrl'
2020-06-08 16:39:26 +03:00
const panels = loadState ( 'dashboard' , 'panels' )
2020-07-31 14:27:43 +03:00
const firstRun = loadState ( 'dashboard' , 'firstRun' )
2020-08-14 17:22:22 +03:00
const background = loadState ( 'dashboard' , 'background' )
2020-08-17 22:29:29 +03:00
const version = loadState ( 'dashboard' , 'version' )
2020-08-18 15:11:02 +03:00
const shippedBackgroundList = loadState ( 'dashboard' , 'shippedBackgrounds' )
2020-08-21 16:25:38 +03:00
const statusInfo = {
weather : {
text : t ( 'dashboard' , 'Weather' ) ,
2020-08-21 18:05:10 +03:00
icon : 'icon-weather-status' ,
2020-08-21 16:25:38 +03:00
} ,
status : {
2020-08-21 23:02:57 +03:00
text : t ( 'dashboard' , 'Status' ) ,
2020-08-21 18:05:10 +03:00
icon : 'icon-user-status-online' ,
2020-08-21 16:25:38 +03:00
} ,
}
2020-08-14 18:21:35 +03:00
2020-06-08 16:39:26 +03:00
export default {
name : 'App' ,
2020-06-15 09:18:50 +03:00
components : {
Modal ,
Draggable ,
2020-08-12 11:02:33 +03:00
BackgroundSettings ,
2020-06-15 09:18:50 +03:00
} ,
2020-08-11 08:54:34 +03:00
mixins : [
isMobile ,
] ,
2020-06-08 16:39:26 +03:00
data ( ) {
return {
2020-08-19 18:04:24 +03:00
isAdmin : getCurrentUser ( ) . isAdmin ,
2020-06-08 16:39:26 +03:00
timer : new Date ( ) ,
2020-08-04 12:58:14 +03:00
registeredStatus : [ ] ,
2020-06-08 16:39:26 +03:00
callbacks : { } ,
2020-08-04 12:58:14 +03:00
callbacksStatus : { } ,
2020-08-21 15:58:12 +03:00
allCallbacksStatus : { } ,
2020-08-21 16:25:38 +03:00
statusInfo ,
2020-08-21 15:58:12 +03:00
enabledStatuses : loadState ( 'dashboard' , 'statuses' ) ,
2020-06-08 16:39:26 +03:00
panels ,
2020-07-31 14:27:43 +03:00
firstRun ,
2020-07-31 14:18:47 +03:00
displayName : getCurrentUser ( ) ? . displayName ,
uid : getCurrentUser ( ) ? . uid ,
2020-06-15 09:18:50 +03:00
layout : loadState ( 'dashboard' , 'layout' ) . filter ( ( panelId ) => panels [ panelId ] ) ,
modal : false ,
2020-08-05 09:29:50 +03:00
appStoreUrl : generateUrl ( '/settings/apps/dashboard' ) ,
2020-08-04 12:58:14 +03:00
statuses : { } ,
2020-08-14 17:22:22 +03:00
background ,
2020-08-17 22:29:29 +03:00
version ,
2020-08-12 11:02:33 +03:00
defaultBackground : window . OCA . Accessibility . theme === 'dark' ? prefixWithBaseUrl ( 'flickr-148302424@N05-36591009215.jpg?v=1' ) : prefixWithBaseUrl ( 'flickr-paszczak000-8715851521.jpg?v=1' ) ,
2020-06-08 16:39:26 +03:00
}
} ,
computed : {
2020-08-11 08:54:34 +03:00
backgroundImage ( ) {
2020-08-17 22:29:29 +03:00
return getBackgroundUrl ( this . background , this . version )
} ,
backgroundStyle ( ) {
if ( this . background . match ( /#[0-9A-Fa-f]{6}/g ) ) {
return null
}
return {
backgroundImage : ` url( ${ this . backgroundImage } ) ` ,
}
2020-08-11 08:54:34 +03:00
} ,
2020-06-08 16:39:26 +03:00
greeting ( ) {
const time = this . timer . getHours ( )
2020-07-31 14:18:47 +03:00
const shouldShowName = this . displayName && this . uid !== this . displayName
2020-06-08 16:39:26 +03:00
if ( time > 18 ) {
2020-08-07 16:57:38 +03:00
return { text : shouldShowName ? t ( 'dashboard' , 'Good evening, {name}' , { name : this . displayName } ) : t ( 'dashboard' , 'Good evening' ) }
2020-06-08 16:39:26 +03:00
}
if ( time > 12 ) {
2020-08-07 16:57:38 +03:00
return { text : shouldShowName ? t ( 'dashboard' , 'Good afternoon, {name}' , { name : this . displayName } ) : t ( 'dashboard' , 'Good afternoon' ) }
2020-06-08 16:39:26 +03:00
}
2020-06-11 05:20:57 +03:00
if ( time > 5 ) {
2020-08-07 16:57:38 +03:00
return { text : shouldShowName ? t ( 'dashboard' , 'Good morning, {name}' , { name : this . displayName } ) : t ( 'dashboard' , 'Good morning' ) }
2020-06-11 05:20:57 +03:00
}
2020-08-11 11:10:24 +03:00
return { text : shouldShowName ? t ( 'dashboard' , 'Good night, {name}' , { name : this . displayName } ) : t ( 'dashboard' , 'Good night' ) }
2020-06-08 16:39:26 +03:00
} ,
2020-06-15 09:18:50 +03:00
isActive ( ) {
return ( panel ) => this . layout . indexOf ( panel . id ) > - 1
} ,
2020-08-21 16:25:38 +03:00
isStatusActive ( ) {
return ( status ) => ! ( status in this . enabledStatuses ) || this . enabledStatuses [ status ]
} ,
2020-08-21 18:05:10 +03:00
sortedAllStatuses ( ) {
return Object . keys ( this . allCallbacksStatus ) . slice ( ) . sort ( ( a , b ) => a > b )
} ,
2020-06-15 09:18:50 +03:00
sortedPanels ( ) {
return Object . values ( this . panels ) . sort ( ( a , b ) => {
const indexA = this . layout . indexOf ( a . id )
const indexB = this . layout . indexOf ( b . id )
if ( indexA === - 1 || indexB === - 1 ) {
return indexB - indexA || a . id - b . id
}
return indexA - indexB || a . id - b . id
} )
} ,
2020-08-20 11:08:30 +03:00
sortedRegisteredStatus ( ) {
return this . registeredStatus . slice ( ) . sort ( ( a , b ) => a > b )
} ,
2020-06-08 16:39:26 +03:00
} ,
watch : {
callbacks ( ) {
2020-06-15 09:18:50 +03:00
this . rerenderPanels ( )
} ,
2020-08-04 12:58:14 +03:00
callbacksStatus ( ) {
for ( const app in this . callbacksStatus ) {
const element = this . $refs [ 'status-' + app ]
if ( this . statuses [ app ] && this . statuses [ app ] . mounted ) {
continue
}
if ( element ) {
this . callbacksStatus [ app ] ( element [ 0 ] )
Vue . set ( this . statuses , app , { mounted : true } )
} else {
console . error ( 'Failed to register panel in the frontend as no backend data was provided for ' + app )
}
}
} ,
2020-06-15 09:18:50 +03:00
} ,
mounted ( ) {
2020-08-18 15:11:02 +03:00
this . updateGlobalStyles ( )
2020-09-17 21:31:21 +03:00
this . updateSkipLink ( )
2020-08-24 15:34:43 +03:00
window . addEventListener ( 'scroll' , this . handleScroll )
2020-08-18 15:11:02 +03:00
2020-06-15 09:18:50 +03:00
setInterval ( ( ) => {
this . timer = new Date ( )
} , 30000 )
2020-08-05 09:29:50 +03:00
if ( this . firstRun ) {
window . addEventListener ( 'scroll' , this . disableFirstrunHint )
}
2020-06-15 09:18:50 +03:00
} ,
2020-08-24 15:34:43 +03:00
destroyed ( ) {
window . removeEventListener ( 'scroll' , this . handleScroll )
} ,
2020-06-15 09:18:50 +03:00
methods : {
/ * *
* Method to register panels that will be called by the integrating apps
*
* @ param { string } app The unique app id for the widget
* @ param { function } callback The callback function to register a panel which gets the DOM element passed as parameter
* /
register ( app , callback ) {
Vue . set ( this . callbacks , app , callback )
} ,
2020-08-04 12:58:14 +03:00
registerStatus ( app , callback ) {
2020-08-21 15:58:12 +03:00
// always save callbacks in case user enables the status later
Vue . set ( this . allCallbacksStatus , app , callback )
// register only if status is enabled or missing from config
2020-08-21 16:25:38 +03:00
if ( this . isStatusActive ( app ) ) {
2020-08-21 15:58:12 +03:00
this . registeredStatus . push ( app )
this . $nextTick ( ( ) => {
Vue . set ( this . callbacksStatus , app , callback )
} )
}
2020-08-04 12:58:14 +03:00
} ,
2020-06-15 09:18:50 +03:00
rerenderPanels ( ) {
2020-06-08 16:39:26 +03:00
for ( const app in this . callbacks ) {
const element = this . $refs [ app ]
2020-07-27 12:17:31 +03:00
if ( this . layout . indexOf ( app ) === - 1 ) {
continue
}
2020-06-15 09:18:50 +03:00
if ( this . panels [ app ] && this . panels [ app ] . mounted ) {
2020-07-10 11:02:44 +03:00
continue
2020-06-08 16:39:26 +03:00
}
if ( element ) {
2020-08-14 17:37:37 +03:00
this . callbacks [ app ] ( element [ 0 ] , {
widget : this . panels [ app ] ,
} )
2020-06-08 16:39:26 +03:00
Vue . set ( this . panels [ app ] , 'mounted' , true )
} else {
console . error ( 'Failed to register panel in the frontend as no backend data was provided for ' + app )
}
}
} ,
2020-06-15 09:18:50 +03:00
saveLayout ( ) {
axios . post ( generateUrl ( '/apps/dashboard/layout' ) , {
layout : this . layout . join ( ',' ) ,
} )
} ,
2020-08-21 15:58:12 +03:00
saveStatuses ( ) {
axios . post ( generateUrl ( '/apps/dashboard/statuses' ) , {
statuses : JSON . stringify ( this . enabledStatuses ) ,
} )
} ,
2020-06-15 09:18:50 +03:00
showModal ( ) {
this . modal = true
2020-08-05 09:29:50 +03:00
this . firstRun = false
2020-06-15 09:18:50 +03:00
} ,
closeModal ( ) {
this . modal = false
} ,
updateCheckbox ( panel , currentValue ) {
const index = this . layout . indexOf ( panel . id )
if ( ! currentValue && index > - 1 ) {
this . layout . splice ( index , 1 )
} else {
this . layout . push ( panel . id )
}
Vue . set ( this . panels [ panel . id ] , 'mounted' , false )
this . saveLayout ( )
this . $nextTick ( ( ) => this . rerenderPanels ( ) )
2020-06-08 16:39:26 +03:00
} ,
2020-08-05 09:29:50 +03:00
disableFirstrunHint ( ) {
window . removeEventListener ( 'scroll' , this . disableFirstrunHint )
setTimeout ( ( ) => {
this . firstRun = false
} , 1000 )
} ,
2020-08-17 22:29:29 +03:00
updateBackground ( data ) {
this . background = data . type === 'custom' || data . type === 'default' ? data . type : data . value
this . version = data . version
2020-08-18 15:11:02 +03:00
this . updateGlobalStyles ( )
} ,
updateGlobalStyles ( ) {
2020-08-18 16:27:16 +03:00
document . body . setAttribute ( 'data-dashboard-background' , this . background )
2020-08-18 15:11:02 +03:00
if ( window . OCA . Theming . inverted ) {
2020-08-19 22:50:40 +03:00
document . body . classList . add ( 'dashboard--inverted' )
2020-08-18 15:11:02 +03:00
}
const shippedBackgroundTheme = shippedBackgroundList [ this . background ] ? shippedBackgroundList [ this . background ] . theming : 'light'
if ( shippedBackgroundTheme === 'dark' ) {
2020-08-19 22:50:40 +03:00
document . body . classList . add ( 'dashboard--dark' )
2020-08-18 15:11:02 +03:00
} else {
2020-08-19 22:50:40 +03:00
document . body . classList . remove ( 'dashboard--dark' )
2020-08-18 15:11:02 +03:00
}
2020-08-12 11:02:33 +03:00
} ,
2020-09-17 21:31:21 +03:00
updateSkipLink ( ) {
// Make sure "Skip to main content" link points to the app content
document . getElementsByClassName ( 'skip-navigation' ) [ 0 ] . setAttribute ( 'href' , '#app-dashboard' )
} ,
2020-08-21 16:25:38 +03:00
updateStatusCheckbox ( app , checked ) {
if ( checked ) {
this . enableStatus ( app )
} else {
this . disableStatus ( app )
}
} ,
2020-08-21 15:58:12 +03:00
enableStatus ( app ) {
this . enabledStatuses [ app ] = true
this . registerStatus ( app , this . allCallbacksStatus [ app ] )
this . saveStatuses ( )
} ,
disableStatus ( app ) {
this . enabledStatuses [ app ] = false
const i = this . registeredStatus . findIndex ( ( s ) => s === app )
if ( i !== - 1 ) {
this . registeredStatus . splice ( i , 1 )
Vue . set ( this . statuses , app , { mounted : false } )
this . $nextTick ( ( ) => {
Vue . delete ( this . callbacksStatus , app )
} )
}
this . saveStatuses ( )
} ,
2020-08-24 15:34:43 +03:00
handleScroll ( ) {
2020-08-24 22:16:31 +03:00
if ( window . scrollY > 70 ) {
2020-08-24 15:34:43 +03:00
document . body . classList . add ( 'dashboard--scrolled' )
} else {
document . body . classList . remove ( 'dashboard--scrolled' )
}
} ,
2020-06-08 16:39:26 +03:00
} ,
}
< / script >
< style lang = "scss" scoped >
2020-08-24 22:49:47 +03:00
# app - dashboard {
width : 100 % ;
background - size : cover ;
background - position : center center ;
background - repeat : no - repeat ;
background - attachment : fixed ;
background - color : var ( -- color - primary ) ;
-- color - background - translucent : rgba ( 255 , 255 , 255 , 0.8 ) ;
-- background - blur : blur ( 10 px ) ;
# body - user . theme -- dark & {
background - color : var ( -- color - main - background ) ;
-- color - background - translucent : rgba ( 24 , 24 , 24 , 0.8 ) ;
2020-08-07 19:34:21 +03:00
}
2020-08-24 22:49:47 +03:00
# body - user . theme -- highcontrast & {
background - color : var ( -- color - main - background ) ;
-- color - background - translucent : var ( -- color - main - background ) ;
2020-06-08 16:39:26 +03:00
}
2020-08-24 22:49:47 +03:00
> h2 {
color : var ( -- color - primary - text ) ;
text - align : center ;
font - size : 32 px ;
line - height : 130 % ;
2020-09-15 16:01:49 +03:00
padding : 10 vh 16 px 0 px ;
2020-08-24 22:49:47 +03:00
}
}
2020-07-22 12:29:35 +03:00
2020-08-24 22:49:47 +03:00
. panels {
width : auto ;
margin : auto ;
max - width : 1500 px ;
display : flex ;
justify - content : center ;
flex - direction : row ;
align - items : flex - start ;
flex - wrap : wrap ;
}
2020-07-10 18:35:18 +03:00
2020-08-24 22:49:47 +03:00
. panel , . panels > div {
width : 320 px ;
max - width : 100 % ;
margin : 16 px ;
background - color : var ( -- color - background - translucent ) ;
- webkit - backdrop - filter : var ( -- background - blur ) ;
backdrop - filter : var ( -- background - blur ) ;
border - radius : var ( -- border - radius - large ) ;
# body - user . theme -- highcontrast & {
border : 2 px solid var ( -- color - border ) ;
}
2020-07-22 12:29:35 +03:00
2020-08-24 22:49:47 +03:00
& . sortable - ghost {
opacity : 0.1 ;
}
2020-07-10 18:35:18 +03:00
2020-08-24 22:49:47 +03:00
& > . panel -- header {
display : flex ;
z - index : 1 ;
top : 50 px ;
padding : 16 px ;
cursor : grab ;
& , : : v - deep * {
- webkit - touch - callout : none ;
- webkit - user - select : none ;
- khtml - user - select : none ;
- moz - user - select : none ;
- ms - user - select : none ;
user - select : none ;
}
2020-06-08 16:39:26 +03:00
2020-08-24 22:49:47 +03:00
& : active {
cursor : grabbing ;
2020-06-11 05:21:24 +03:00
}
2020-07-10 18:35:18 +03:00
2020-08-24 22:49:47 +03:00
a {
flex - grow : 1 ;
2020-07-10 18:35:18 +03:00
}
2020-08-20 13:38:17 +03:00
2020-08-24 22:49:47 +03:00
> h2 {
display : block ;
flex - grow : 1 ;
margin : 0 ;
font - size : 20 px ;
line - height : 24 px ;
font - weight : bold ;
background - size : 32 px ;
background - position : 14 px 12 px ;
padding : 16 px 8 px 16 px 60 px ;
height : 56 px ;
white - space : nowrap ;
overflow : hidden ;
text - overflow : ellipsis ;
cursor : grab ;
2020-08-20 13:38:17 +03:00
}
2020-06-08 16:39:26 +03:00
}
2020-08-24 22:49:47 +03:00
& > . panel -- content {
margin : 0 16 px 16 px 16 px ;
height : 420 px ;
// We specifically do not want scrollbars inside widgets
overflow : hidden ;
}
2020-08-12 09:10:58 +03:00
2020-08-24 22:49:47 +03:00
// No need to extend height of widgets if only one column is shown
@ media only screen and ( max - width : 709 px ) {
& > . panel -- content {
height : auto ;
2020-08-12 09:10:58 +03:00
}
}
2020-08-24 22:49:47 +03:00
}
2020-08-12 09:10:58 +03:00
2020-08-24 22:49:47 +03:00
. footer {
text - align : center ;
transition : bottom var ( -- animation - slow ) ease - in - out ;
bottom : 0 ;
padding : 44 px 0 ;
}
2020-08-19 14:54:50 +03:00
2020-08-24 22:49:47 +03:00
. edit - panels {
display : inline - block ;
margin : auto ;
background - position : 16 px center ;
padding : 12 px 16 px ;
padding - left : 36 px ;
border - radius : var ( -- border - radius - pill ) ;
max - width : 200 px ;
opacity : 1 ;
text - align : center ;
}
2020-08-05 09:29:50 +03:00
2020-08-24 22:49:47 +03:00
. edit - panels ,
2020-09-15 15:48:03 +03:00
. statuses : : v - deep . action - item . action - item _ _menutoggle ,
2020-08-24 22:49:47 +03:00
. statuses : : v - deep . action - item . action - item -- open . action - item _ _menutoggle {
background - color : var ( -- color - background - translucent ) ;
- webkit - backdrop - filter : var ( -- background - blur ) ;
backdrop - filter : var ( -- background - blur ) ;
& : hover ,
& : focus ,
& : active {
background - color : var ( -- color - background - hover ) ;
2020-06-15 09:18:50 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-06-15 09:18:50 +03:00
2020-08-24 22:49:47 +03:00
. modal _ _content {
padding : 32 px 16 px ;
max - height : 70 vh ;
text - align : center ;
overflow : auto ;
2020-08-17 02:17:06 +03:00
2020-08-24 22:49:47 +03:00
ol {
display : flex ;
flex - direction : row ;
justify - content : center ;
list - style - type : none ;
padding - bottom : 16 px ;
}
li {
label {
display : block ;
padding : 48 px 8 px 16 px 8 px ;
margin : 8 px ;
width : 160 px ;
background - color : var ( -- color - background - hover ) ;
border : 2 px solid var ( -- color - main - background ) ;
border - radius : var ( -- border - radius - large ) ;
background - size : 24 px ;
background - position : center 16 px ;
text - align : center ;
& : hover {
2020-08-17 02:17:06 +03:00
border - color : var ( -- color - primary ) ;
}
2020-06-15 09:18:50 +03:00
}
2020-08-11 17:45:02 +03:00
2020-08-24 22:49:47 +03:00
input : focus + label {
border - color : var ( -- color - primary ) ;
2020-08-11 17:45:02 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-08-20 19:07:27 +03:00
2020-08-24 22:49:47 +03:00
h3 {
font - weight : bold ;
& : not ( : first - of - type ) {
margin - top : 64 px ;
2020-08-20 19:07:27 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-08-20 11:08:30 +03:00
2020-08-24 22:49:47 +03:00
// Adjust design of 'Get more widgets' button
. button {
display : inline - block ;
2020-09-15 16:06:06 +03:00
padding : 10 px 16 px ;
2020-08-24 22:49:47 +03:00
margin : 0 ;
}
2020-08-20 11:08:30 +03:00
2020-08-24 22:49:47 +03:00
p {
max - width : 650 px ;
margin : 0 auto ;
a : hover ,
a : focus {
border - bottom : 2 px solid var ( -- color - border ) ;
2020-08-20 11:08:30 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-08-20 11:08:30 +03:00
2020-08-24 22:49:47 +03:00
. credits -- end {
padding - bottom : 32 px ;
color : var ( -- color - text - maxcontrast ) ;
2020-08-20 11:08:30 +03:00
2020-08-24 22:49:47 +03:00
a {
color : var ( -- color - text - maxcontrast ) ;
2020-08-20 11:08:30 +03:00
}
2020-06-15 09:18:50 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-06-15 09:18:50 +03:00
2020-08-24 22:49:47 +03:00
. flip - list - move {
transition : transform var ( -- animation - slow ) ;
}
2020-06-15 09:18:50 +03:00
2020-08-24 22:49:47 +03:00
. statuses {
display : flex ;
flex - direction : row ;
justify - content : center ;
flex - wrap : wrap ;
margin - bottom : 36 px ;
2020-08-04 12:58:14 +03:00
2020-08-24 22:49:47 +03:00
& > div {
margin : 8 px ;
2020-08-04 12:58:14 +03:00
}
2020-08-24 22:49:47 +03:00
}
2020-06-08 16:39:26 +03:00
< / style >