|
|
|
|
@ -25,30 +25,41 @@ |
|
|
|
|
|
|
|
|
|
<template> |
|
|
|
|
<div class="background-selector"> |
|
|
|
|
<!-- Custom background --> |
|
|
|
|
<button class="background filepicker" |
|
|
|
|
:class="{ active: background === 'custom' }" |
|
|
|
|
tabindex="0" |
|
|
|
|
@click="pickFile"> |
|
|
|
|
{{ t('theming', 'Pick from Files') }} |
|
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
<!-- Default background --> |
|
|
|
|
<button class="background default" |
|
|
|
|
tabindex="0" |
|
|
|
|
:class="{ 'icon-loading': loading === 'default', active: background === 'default' }" |
|
|
|
|
@click="setDefault"> |
|
|
|
|
{{ t('theming', 'Default image') }} |
|
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
<!-- Default admin primary color --> |
|
|
|
|
<button class="background color" |
|
|
|
|
:class="{ active: background.startsWith('#') }" |
|
|
|
|
tabindex="0" |
|
|
|
|
:data-color="Theming.defaultColor" |
|
|
|
|
:data-color-bright="invertTextColor(Theming.defaultColor)" |
|
|
|
|
:style="{ color: invertTextColor(Theming.defaultColor) ? '#000000' : '#ffffff'}" |
|
|
|
|
@click="pickColor"> |
|
|
|
|
{{ t('theming', 'Plain background') }} |
|
|
|
|
</button> |
|
|
|
|
|
|
|
|
|
<!-- Background set selection --> |
|
|
|
|
<button v-for="shippedBackground in shippedBackgrounds" |
|
|
|
|
:key="shippedBackground.name" |
|
|
|
|
v-tooltip="shippedBackground.details.attribution" |
|
|
|
|
:class="{ 'icon-loading': loading === shippedBackground.name, active: background === shippedBackground.name }" |
|
|
|
|
tabindex="0" |
|
|
|
|
class="background" |
|
|
|
|
:data-color-bright="shippedBackground.details.theming === 'dark'" |
|
|
|
|
:style="{ 'background-image': 'url(' + shippedBackground.preview + ')' }" |
|
|
|
|
@click="setShipped(shippedBackground.name)" /> |
|
|
|
|
</div> |
|
|
|
|
@ -69,6 +80,7 @@ export default { |
|
|
|
|
directives: { |
|
|
|
|
Tooltip, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
props: { |
|
|
|
|
background: { |
|
|
|
|
type: String, |
|
|
|
|
@ -79,12 +91,15 @@ export default { |
|
|
|
|
default: '', |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
data() { |
|
|
|
|
return { |
|
|
|
|
backgroundImage: generateUrl('/apps/theming/background') + '?v=' + Date.now(), |
|
|
|
|
loading: false, |
|
|
|
|
Theming: loadState('theming', 'data', {}), |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
computed: { |
|
|
|
|
shippedBackgrounds() { |
|
|
|
|
return Object.keys(shippedBackgroundList).map(fileName => { |
|
|
|
|
@ -97,7 +112,27 @@ export default { |
|
|
|
|
}) |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
methods: { |
|
|
|
|
invertTextColor(color) { |
|
|
|
|
const l = this.calculateLuma(color) |
|
|
|
|
if (l > 0.6) { |
|
|
|
|
return true |
|
|
|
|
} else { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
calculateLuma(color) { |
|
|
|
|
const [red, green, blue] = this.hexToRGB(color) |
|
|
|
|
return (0.2126 * red + 0.7152 * green + 0.0722 * blue) / 255 |
|
|
|
|
}, |
|
|
|
|
hexToRGB(hex) { |
|
|
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) |
|
|
|
|
return result |
|
|
|
|
? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] |
|
|
|
|
: null |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
async update(data) { |
|
|
|
|
const background = data.type === 'custom' || data.type === 'default' ? data.type : data.value |
|
|
|
|
this.backgroundImage = getBackgroundUrl(background, data.version, this.themingDefaultBackground) |
|
|
|
|
@ -128,9 +163,9 @@ export default { |
|
|
|
|
const result = await axios.post(generateUrl('/apps/theming/background/custom'), { value: path }) |
|
|
|
|
this.update(result.data) |
|
|
|
|
}, |
|
|
|
|
async pickColor() { |
|
|
|
|
async pickColor(event) { |
|
|
|
|
this.loading = 'color' |
|
|
|
|
const color = OCA && OCA.Theming ? OCA.Theming.color : '#0082c9' |
|
|
|
|
const color = event?.target?.dataset?.color || this.Theming?.color || '#0082c9' |
|
|
|
|
const result = await axios.post(generateUrl('/apps/theming/background/color'), { value: color }) |
|
|
|
|
this.update(result.data) |
|
|
|
|
}, |
|
|
|
|
@ -171,7 +206,7 @@ export default { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.color { |
|
|
|
|
background-color: var(--color-main-background-not-plain, var(--color-primary)); |
|
|
|
|
background-color: var(--color-primary-default); |
|
|
|
|
color: var(--color-primary-text); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -181,14 +216,20 @@ export default { |
|
|
|
|
border: 2px solid var(--color-primary); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.active:not(.icon-loading):after { |
|
|
|
|
background-image: var(--icon-checkmark-white); |
|
|
|
|
background-repeat: no-repeat; |
|
|
|
|
background-position: center; |
|
|
|
|
background-size: 44px; |
|
|
|
|
content: ''; |
|
|
|
|
display: block; |
|
|
|
|
height: 100%; |
|
|
|
|
&.active:not(.icon-loading) { |
|
|
|
|
&:after { |
|
|
|
|
background-image: var(--icon-checkmark-white); |
|
|
|
|
background-repeat: no-repeat; |
|
|
|
|
background-position: center; |
|
|
|
|
background-size: 44px; |
|
|
|
|
content: ''; |
|
|
|
|
display: block; |
|
|
|
|
height: 100%; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&[data-color-bright]:after { |
|
|
|
|
background-image: var(--icon-checkmark-dark); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|