refactoring: update severals components

This commit is contained in:
Simon Vieille
2025-04-04 20:13:15 +02:00
parent 4f261c434d
commit d8a622ce0f
37 changed files with 1857 additions and 1782 deletions
+81 -45
View File
@@ -16,73 +16,86 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<div>
<ul class="side-menu-setting-list" :class="{hide: values.length === 0}">
<li v-for="item in values" class="side-menu-setting-list-item" v-on:click="showEditForm(item)">
<span v-text="item.en"></span>
<ul
class="side-menu-setting-list"
:class="{ hide: values.length === 0 }"
>
<li
v-for="(item, key) in values"
:key="key"
class="side-menu-setting-list-item"
@click="showEditForm(item)"
>
{{ item.en }}
</li>
</ul>
<NcActions>
<NcActionButton @click="showAddForm" icon="icon-add"></NcActionButton>
<NcActionButton
icon="icon-add"
@click="showAddForm"
></NcActionButton>
</NcActions>
<NcModal v-if="addForm" @close="hideAddForm">
<NcModal
v-if="addForm"
@close="hideAddForm"
>
<div class="modal__content">
<div v-for="lang in langs">
<span class="lang" v-text="lang"></span>
<input type="text" v-model="newValue[lang]" required style="width: calc(100% - 100px)">
<div v-for="(lang, key) in langs" :key="key">
<span class="lang">{{ lang }}</span>
<input
v-model="newValue[lang]"
type="text"
required
style="width: calc(100% - 100px)"
/>
</div>
<NcActions>
<NcActionButton @click="saveAdd" icon="icon-checkmark"></NcActionButton>
<NcActionButton
icon="icon-checkmark"
@click="saveAdd"
></NcActionButton>
</NcActions>
</div>
</NcModal>
<NcModal v-if="editForm" @close="hideEditForm">
<NcModal
v-if="editForm"
@close="hideEditForm"
>
<div class="modal__content">
<div v-for="lang in langs">
<span class="lang" v-text="lang"></span>
<input type="text" v-model="editValue[lang]" required style="width: calc(100% - 100px)">
<div v-for="(lang, key) in langs" :key="key">
<span class="lang">{{ lang }}</span>
<input
v-model="editValue[lang]"
type="text"
required
style="width: calc(100% - 100px)"
/>
</div>
<div class="pull-right">
<NcActions>
<NcActionButton @click="removeEdit" icon="icon-delete"></NcActionButton>
<NcActionButton
icon="icon-delete"
@click="removeEdit"
></NcActionButton>
</NcActions>
</div>
<NcActions>
<NcActionButton @click="saveEdit" icon="icon-checkmark"></NcActionButton>
<NcActionButton
icon="icon-checkmark"
@click="saveEdit"
></NcActionButton>
</NcActions>
</div>
</NcModal>
</div>
</template>
<style>
.modal__content {
padding: 10px;
}
.modal__content .lang {
width: 60px;
display: inline-block;
padding: 4px;
box-sizing: border-box;
}
.pull-right {
float: right;
}
</style>
<style scoped>
.hide {
display: none;
}
</style>
<script>
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
@@ -106,6 +119,10 @@ export default {
editValue: {},
}
},
mounted() {
this.input = document.querySelector('input[name="categories-custom"]')
this.init()
},
methods: {
init() {
this.values = JSON.parse(this.input.value)
@@ -115,12 +132,12 @@ export default {
this.input.value = JSON.stringify(this.values)
},
showAddForm() {
this.newValue = {id: 'cat' + Math.random().toString().replace('0.', '')}
this.newValue = { id: 'cat' + Math.random().toString().replace('0.', '') }
this.addForm = true
},
showEditForm(value) {
this.editValue = {id: value.id}
this.editValue = { id: value.id }
for (let i of this.langs) {
this.editValue[i] = typeof value[i] !== 'undefined' ? value[i] : ''
@@ -159,7 +176,7 @@ export default {
removeEdit() {
for (let i in this.values) {
if (this.values[i].id === this.editValue.id) {
this.values.splice(i, 1);
this.values.splice(i, 1)
}
}
@@ -173,9 +190,28 @@ export default {
this.editForm = false
},
},
mounted() {
this.input = document.querySelector('input[name="categories-custom"]')
this.init()
}
}
</script>
<style>
.modal__content {
padding: 10px;
}
.modal__content .lang {
width: 60px;
display: inline-block;
padding: 4px;
box-sizing: border-box;
}
.pull-right {
float: right;
}
</style>
<style scoped>
.hide {
display: none;
}
</style>
+61 -32
View File
@@ -1,4 +1,3 @@
<!--
- @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
-
@@ -26,45 +25,70 @@
:aria-label="t('core', 'Applications menu')"
>
<ul
v-if="appList.length"
class="app-menu-main"
:class="{ 'app-menu-main__hidden-label': hiddenLabels === 1, 'app-menu-main__show-hovered': hiddenLabels === 2 }"
v-if="appList.length"
>
<li v-for="app in mainAppList(state)"
>
<li
v-for="app in mainAppList(state)"
:key="app.id"
:data-app-id="app.id"
class="app-menu-entry"
:class="{ 'app-menu-entry__active': app.active, 'app-menu-entry__hidden-label': hiddenLabels === 1, 'app-menu-main__show-hovered': hiddenLabels === 2 }"
:style="makeStyle(app)"
>
<a :href="app.href"
>
<a
:href="app.href"
:class="{ 'has-unread': app.unread > 0 }"
:aria-label="appLabel(app)"
:target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined"
:aria-current="app.active ? 'page' : false">
<img :src="app.icon" alt="">
:aria-current="app.active ? 'page' : false"
>
<img
:src="app.icon"
alt=""
/>
<div class="app-menu-entry--label">
{{ app.name }}
<span v-if="app.unread > 0" class="hidden-visually unread-counter">{{ app.unread }}</span>
<span
v-if="app.unread > 0"
class="hidden-visually unread-counter"
>{{ app.unread }}</span
>
</div>
</a>
</li>
</ul>
<NcActions class="app-menu-more" :aria-label="t('core', 'More apps')">
<NcActionLink v-for="app in popoverAppList(state)"
<NcActions
class="app-menu-more"
:aria-label="t('core', 'More apps')"
>
<NcActionLink
v-for="app in popoverAppList(state)"
:key="app.id"
:aria-label="appLabel(app)"
:aria-current="app.active ? 'page' : false"
:href="app.href"
:style="makeStyle(app)"
class="app-menu-popover-entry">
class="app-menu-popover-entry"
>
<template #icon>
<div class="app-icon" :class="{ 'has-unread': app.unread > 0 }">
<img :src="app.icon" alt="">
<div
class="app-icon"
:class="{ 'has-unread': app.unread > 0 }"
>
<img
:src="app.icon"
alt=""
/>
</div>
</template>
{{ app.name }}
<span v-if="app.unread > 0" class="hidden-visually unread-counter">{{ app.unread }}</span>
<span
v-if="app.unread > 0"
class="hidden-visually unread-counter"
>{{ app.unread }}</span
>
</NcActionLink>
</NcActions>
</nav>
@@ -91,8 +115,8 @@ export default defineComponent({
setup() {
return {
t,
n,
t,
n,
}
},
@@ -108,7 +132,8 @@ export default defineComponent({
},
mounted() {
axios.get(generateOcsUrl('core/navigation', 2) + '/apps?format=json')
axios
.get(generateOcsUrl('core/navigation', 2) + '/apps?format=json')
.then((response) => response.data)
.then((data) => {
if (data.ocs.meta.statuscode !== 200) {
@@ -181,16 +206,18 @@ export default defineComponent({
},
appLabel(app) {
return app.name
+ (app.active ? ' (' + t('core', 'Currently open') + ')' : '')
+ (app.unread > 0 ? ' (' + n('core', '{count} notification', '{count} notifications', app.unread, { count: app.unread }) + ')' : '')
return (
app.name +
(app.active ? ' (' + t('core', 'Currently open') + ')' : '') +
(app.unread > 0 ? ' (' + n('core', '{count} notification', '{count} notifications', app.unread, { count: app.unread }) + ')' : '')
)
},
makeStyle(app) {
if (app.order !== null) {
return `order: ${app.order}`
}
}
},
},
})
</script>
@@ -219,7 +246,7 @@ $header-icon-size: 20px;
opacity: 1;
&::before {
content: " ";
content: ' ';
position: absolute;
pointer-events: none;
border-bottom-color: var(--color-main-background);
@@ -312,7 +339,8 @@ $header-icon-size: 20px;
bottom: 0;
}
&::before, .app-menu-entry::before {
&::before,
.app-menu-entry::before {
opacity: 0;
}
}
@@ -328,18 +356,19 @@ $header-icon-size: 20px;
bottom: 0;
}
&::before, .app-menu-entry::before {
&::before,
.app-menu-entry::before {
opacity: 0;
}
}
}
::v-deep .app-menu-more .button-vue--vue-tertiary {
opacity: .7;
opacity: 0.7;
margin: 3px;
filter: var(--background-image-invert-if-bright, var(--primary-invert-if-bright));
&:not([aria-expanded="true"]) {
&:not([aria-expanded='true']) {
color: var(--color-main-text);
&:hover {
@@ -348,10 +377,10 @@ $header-icon-size: 20px;
}
}
&:focus-visible {
opacity: 1;
outline: none !important;
}
&:focus-visible {
opacity: 1;
outline: none !important;
}
}
.app-menu-popover-entry {
@@ -376,7 +405,7 @@ $header-icon-size: 20px;
}
.has-unread::after {
content: "";
content: '';
width: 8px;
height: 8px;
background-color: var(--color-primary-element-text);
+13 -9
View File
@@ -16,17 +16,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<div class="side-menu-search">
<input type="text" :value="value" :placeholder="t('side_menu', 'Search')" @input="$emit('input', $event.target.value)">
<input
type="text"
:value="value"
:placeholder="t('side_menu', 'Search')"
@input="emit('input', $event.target.value)"
/>
</div>
</template>
<script>
export default {
name: 'AppSearch',
props: {
value: {
required: true
},
<script setup>
const emit = defineEmit('input')
const { value } = defineProps({
value: {
type: String,
required: true,
},
}
})
</script>
+5 -13
View File
@@ -15,18 +15,10 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<button class="side-menu-opener side-menu-closer" :arial-label="label">
<span v-text="label"></span>
<button
class="side-menu-opener side-menu-closer"
:arial-label="label"
>
<span>{{ t('side_menu', 'Close the menu') }}</span>
</button>
</template>
<script>
export default {
name: 'CloserButton',
data() {
return {
label: t('side_menu', 'Close the menu'),
}
}
}
</script>
+22 -11
View File
@@ -16,10 +16,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<div class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<svg
width="38"
height="38"
viewBox="0 0 38 38"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
>
<g
transform="translate(1 1)"
stroke-width="2"
>
<circle
stroke-opacity=".5"
cx="18"
cy="18"
r="18"
/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
@@ -27,16 +43,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
repeatCount="indefinite"
/>
</path>
</g>
</g>
</svg>
</div>
</template>
<script>
export default {
name: 'Loader',
}
</script>
+29 -21
View File
@@ -15,30 +15,38 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<div v-bind:class="classes">
<a v-if="link !== null" v-bind:href="link">
<img v-bind:src="image" alt="Logo">
<div :class="classes">
<a
v-if="link !== null"
:href="link"
>
<img
:src="image"
alt="Logo"
/>
</a>
<img v-else v-bind:src="image" alt="Logo">
<img
v-else
:src="image"
alt="Logo"
/>
</div>
</template>
<script>
export default {
name: 'Logo',
props: {
image: {
type: String,
required: true
},
link: {
type: String,
required: false
},
classes: {
type: Object,
required: true
},
<script setup>
const { image, link, classes } = defineProps({
image: {
type: String,
required: true,
},
}
link: {
type: String,
required: false,
default: null,
},
classes: {
type: Object,
required: true,
},
})
</script>
+5 -13
View File
@@ -15,18 +15,10 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<button class="side-menu-opener" :arial-label="label">
<span v-text="label"></span>
<button
class="side-menu-opener"
:arial-label="label"
>
<span>{{ t('side_menu', 'Toggle the menu') }}</span>
</button>
</template>
<script>
export default {
name: 'OpenerButton',
data() {
return {
label: t('side_menu', 'Toggle the menu'),
}
}
}
</script>
+19 -19
View File
@@ -16,34 +16,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<div class="side-menu-settings">
<a v-bind:href="href">
<a :href="href">
<!--
{{ label }}
-->
<span class="avatardiv avatardiv-shown">
<img v-bind:src="avatar" :alt="label">
<img
:src="avatar"
:alt="label"
/>
</span>
</a>
</div>
</template>
<script>
export default {
name: 'SettingsButton',
props: {
label: {
type: String,
required: true
},
href: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
<script setup>
const { label, href, avatar } = defineProps({
label: {
type: String,
required: true,
},
}
href: {
type: String,
required: true,
},
avatar: {
type: String,
required: true,
},
})
</script>
+35 -29
View File
@@ -15,38 +15,44 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label">
<img class="side-menu-app-icon" v-bind:src="icon" v-bind:alt="label" />
<span class="side-menu-app-text" v-text="label"></span>
<li :class="classes">
<a
:href="href"
:target="target"
:title="label"
>
<img
class="side-menu-app-icon"
:src="icon"
:alt="label"
/>
<span class="side-menu-app-text">{{ label }}</span>
</a>
</li>
</template>
<script>
export default {
name: 'SideMenuApp',
props: {
label: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
<script setup>
const { label, icon, href, classes, target } = defineProps({
label: {
type: String,
required: true,
},
}
icon: {
type: String,
required: true,
},
href: {
type: String,
required: true,
},
classes: {
type: Object,
required: true,
},
target: {
type: String,
required: false,
default: null,
},
})
</script>
+17 -8
View File
@@ -16,34 +16,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<li :class="classes">
<a :href="href" :target="target" :title="label">
<img class="side-menu-app-icon" :src="icon" :alt="label" />
<a
:href="href"
:target="target"
:title="label"
>
<img
class="side-menu-app-icon"
:src="icon"
:alt="label"
/>
<span class="side-menu-app-text">{{ label }}</span>
</a>
</li>
</template>
<script setup>
defineProps({
const { label, icon, href, classes, target } = defineProps({
label: {
type: String,
required: true
required: true,
},
icon: {
type: String,
required: true
required: true,
},
href: {
type: String,
required: true
required: true,
},
classes: {
type: Object,
required: true
required: true,
},
target: {
type: String,
required: false
required: false,
default: null,
},
})
</script>