Replacing css icons with md components

Signed-off-by: dartcafe <github@dartcafe.de>
This commit is contained in:
dartcafe 2022-05-27 21:24:44 +02:00
Родитель c6717a0799
Коммит 54f8ff75da
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: CCE73CEF3035D3C8
23 изменённых файлов: 592 добавлений и 336 удалений

Просмотреть файл

@ -22,56 +22,10 @@
} }
:root { :root {
--icon-md-account-check: url('../icons/material-design/account-check.svg');
--icon-md-account-group: url('../icons/material-design/account-group.svg');
--icon-md-account-cog: url('../icons/material-design/account-cog.svg');
--icon-md-archive: url('../icons/material-design/archive.svg');
--icon-md-bell: url('../icons/material-design/bell.svg');
--icon-md-bell-off: url('../icons/material-design/bell-off.svg');
--icon-md-cancel: url('../icons/material-design/cancel.svg');
--icon-md-calendar-month: url('../icons/material-design/calendar-month.svg');
--icon-md-calendar-blank: url('../icons/material-design/calendar-blank.svg');
--icon-md-calendar-end: url('../icons/material-design/calendar-end.svg');
--icon-md-check: url('../icons/material-design/check.svg');
--icon-md-clipboard-arrow-left-outline: url('../icons/material-design/clipboard-arrow-left-outline.svg');
--icon-md-close: url('../icons/material-design/close.svg');
--icon-md-clock-outline: url('../icons/material-design/clock-outline.svg');
--icon-md-checkbox-marked-outline: url('../icons/material-design/checkbox-marked-outline.svg');
--icon-md-cog: url('../icons/material-design/cog.svg');
--icon-md-comment-processing: url('../icons/material-design/comment-processing.svg');
--icon-md-content-copy: url('../icons/material-design/content-copy.svg');
--icon-md-crown: url('../icons/material-design/crown.svg');
--icon-md-delete: url('../icons/material-design/delete.svg');
--icon-md-earth: url('../icons/material-design/earth.svg');
--icon-md-email: url('../icons/material-design/email.svg');
--icon-md-email-edit-outline: url('../icons/material-design/email-edit-outline.svg');
--icon-md-exclamation-thick: url('../icons/material-design/exclamation-thick.svg');
--icon-md-format-list-bulleted-square: url('../icons/material-design/format-list-bulleted-square.svg');
--icon-md-format-list-checkbox: url('../icons/material-design/format-list-checkbox.svg');
--icon-md-format-list-numbered: url('../icons/material-design/format-list-numbered.svg');
--icon-md-format-list-checks: url('../icons/material-design/format-list-checks.svg');
--icon-md-incognito: url('../icons/material-design/incognito.svg');
--icon-md-link-variant: url('../icons/material-design/link-variant.svg');
--icon-md-lock: url('../icons/material-design/lock.svg');
--icon-md-lock-open-variant: url('../icons/material-design/lock-open-variant.svg');
--icon-md-key: url('../icons/material-design/key.svg');
--icon-md-map-clock-outline: url('../icons/material-design/map-clock-outline.svg');
--icon-md-monitor: url('../icons/material-design/monitor.svg');
--icon-md-monitor-lock: url('../icons/material-design/monitor-lock.svg');
--icon-md-monitor-off: url('../icons/material-design/monitor-off.svg');
--icon-md-offer: url('../icons/material-design/offer.svg');
--icon-md-poll: url('../icons/material-design/poll.svg');
--icon-md-polls-maybe: url('../icons/material-design/polls-maybe.svg');
--icon-md-publish-off: url('../icons/material-design/publish-off.svg');
--icon-md-recycle: url('../icons/material-design/recycle.svg');
--icon-md-share-variant: url('../icons/material-design/share-variant.svg');
--icon-md-shield-crown-outline: url('../icons/material-design/shield-crown-outline.svg'); --icon-md-shield-crown-outline: url('../icons/material-design/shield-crown-outline.svg');
--icon-md-polls-shield-crown-outline-strike-thru: url('../icons/material-design/polls-shield-crown-outline-strike-thru.svg'); --icon-md-email: url('../icons/material-design/email.svg');
--icon-md-sort-clock-ascending-outline: url('../icons/material-design/sort-clock-ascending-outline.svg'); --icon-md-share-variant: url('../icons/material-design/share-variant.svg');
--icon-md-undo: url('../icons/material-design/undo.svg'); --icon-md-link-variant: url('../icons/material-design/link-variant.svg');
--icon-md-vector-combine: url('../icons/material-design/vector-combine.svg');
--icon-md-wrench: url('../icons/material-design/wrench.svg');
--icon-size: 18px; --icon-size: 18px;
--icon-md-color-default: #000; --icon-md-color-default: #000;
@ -99,80 +53,6 @@
.icon-svg-md-link { @include svg-icon(var(--icon-md-link-variant)); } .icon-svg-md-link { @include svg-icon(var(--icon-md-link-variant)); }
// mask icons // mask icons
// UserItem.vue
.icon-mask-md-admin { @include masked-icon(var(--icon-md-shield-crown-outline)); } .icon-mask-md-admin { @include masked-icon(var(--icon-md-shield-crown-outline)); }
.icon-mask-md-admin-remove { @include masked-icon(var(--icon-md-shield-crown-outline-strike-thru)); }
.icon-mask-md-anonymous-poll { @include masked-icon(var(--icon-md-incognito)); }
.icon-mask-md-archive-poll { @include masked-icon(var(--icon-md-archive)); }
.icon-mask-md-archived-poll { @include masked-icon(var(--icon-md-archive)); }
.icon-mask-md-clippy { @include masked-icon(var(--icon-md-clipboard-arrow-left-outline)); }
.icon-mask-md-clone-poll { @include masked-icon(var(--icon-md-content-copy)); }
.icon-mask-md-closed-poll { @include masked-icon(var(--icon-md-lock)); }
.icon-mask-md-creation { @include masked-icon(var(--icon-md-clock-outline)); }
.icon-mask-md-date-options { @include masked-icon(var(--icon-md-calendar-month)); }
.icon-mask-md-date-poll { @include masked-icon(var(--icon-md-calendar-blank)); }
.icon-mask-md-delete-poll { @include masked-icon(var(--icon-md-delete)); }
.icon-mask-md-edit-email-address { @include masked-icon(var(--icon-md-email-edit-outline)); }
.icon-mask-md-email { @include masked-icon(var(--icon-md-email)); }
.icon-mask-md-expiration { @include masked-icon(var(--icon-md-calendar-end)); }
.icon-mask-md-hide-results-until-closed { @include masked-icon(var(--icon-md-monitor-lock)); }
.icon-mask-md-navigation-administration { @include masked-icon(var(--icon-md-cog)); }
.icon-mask-md-navigation-all { @include masked-icon(var(--icon-md-poll)); }
.icon-mask-md-navigation-archived { @include masked-icon(var(--icon-md-archive)); }
.icon-mask-md-navigation-closed { @include masked-icon(var(--icon-md-lock)); }
.icon-mask-md-navigation-combo { @include masked-icon(var(--icon-md-vector-combine)); }
.icon-mask-md-navigation-my { @include masked-icon(var(--icon-md-crown)); }
.icon-mask-md-navigation-open { @include masked-icon(var(--icon-md-earth)); }
.icon-mask-md-navigation-participated { @include masked-icon(var(--icon-md-account-check)); }
.icon-mask-md-navigation-personal-settings { @include masked-icon(var(--icon-md-account-cog)); }
.icon-mask-md-navigation-private { @include masked-icon(var(--icon-md-key)); }
.icon-mask-md-navigation-relevant { @include masked-icon(var(--icon-md-exclamation-thick)); }
.icon-mask-md-open-poll { @include masked-icon(var(--icon-md-earth)); }
.icon-mask-md-options { @include masked-icon(var(--icon-md-format-list-checkbox)); }
.icon-mask-md-options-order-date { @include masked-icon(var(--icon-md-sort-clock-ascending-outline)); }
.icon-mask-md-options-order-original { @include masked-icon(var(--icon-md-format-list-bulleted-square)); }
.icon-mask-md-options-order-ranked { @include masked-icon(var(--icon-md-format-list-numbered)); }
.icon-mask-md-owner { @include masked-icon(var(--icon-md-crown)); }
.icon-mask-md-participants { @include masked-icon(var(--icon-md-account-group)); }
.icon-mask-md-private-poll { @include masked-icon(var(--icon-md-key)); }
.icon-mask-md-proposals-allowed { @include masked-icon(var(--icon-md-offer)); }
.icon-mask-md-proposals { @include masked-icon(var(--icon-md-offer)); }
.icon-mask-md-send-link-per-email { @include masked-icon(var(--icon-md-link-variant)); }
.icon-mask-md-show-results { @include masked-icon(var(--icon-md-monitor)); }
.icon-mask-md-show-results-never { @include masked-icon(var(--icon-md-monitor-off)); }
.icon-mask-md-sidebar-comments { @include masked-icon(var(--icon-md-comment-processing)); }
.icon-mask-md-sidebar-configuration { @include masked-icon(var(--icon-md-wrench)); }
.icon-mask-md-sidebar-options { @include masked-icon(var(--icon-md-format-list-checks)); }
.icon-mask-md-sidebar-share { @include masked-icon(var(--icon-md-share-variant)); }
.icon-mask-md-subscribed { @include masked-icon(var(--icon-md-bell)); }
.icon-mask-md-reset-votes { @include masked-icon(var(--icon-md-undo)); }
.icon-mask-md-restore-poll { @include masked-icon(var(--icon-md-recycle)); }
.icon-mask-md-text-poll { @include masked-icon(var(--icon-md-format-list-bulleted-square)); }
.icon-mask-md-timezone { @include masked-icon(var(--icon-md-map-clock-outline)); }
.icon-mask-md-unsubscribed { @include masked-icon(var(--icon-md-bell-off)); }
.icon-mask-md-unpublished-poll { @include masked-icon(var(--icon-md-publish-off)); }
.icon-mask-md-yes-vote,
.icon-mask-md-yes-votes {
background-color: var(--color-polls-foreground-yes) !important;
@include masked-icon(var(--icon-md-check));
}
.icon-mask-md-no-vote,
.icon-mask-md-no-votes {
background-color: var(--color-polls-foreground-no) !important;
@include masked-icon(var(--icon-md-close));
}
.locked .vote-item.currentuser .icon,
.icon-mask-md-locked-vote {
background-color: var(--color-polls-foreground-no) !important;
@include masked-icon(var(--icon-md-cancel));
mask-size: 100%;
-webkit-mask-size: 100%;
}
.icon-mask-md-maybe-vote,
.icon-mask-md-maybe-votes {
background-color: var(--color-polls-foreground-maybe) !important;
@include masked-icon(var(--icon-md-polls-maybe));
}

Просмотреть файл

@ -0,0 +1,56 @@
<template>
<span :aria-hidden="!title"
:aria-label="title"
class="material-design-icon circles-app-icon"
role="img"
v-bind="$attrs"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 57 57">
<path d="M7.1 28.5A21.4 21.4 0 0 1 28.5 7.1m10.7 40A21.4 21.4 0 0 1 10 39M39.2 10A21.4 21.4 0 0 1 47 39.2"
fill="none"
:stroke="fillcolor"
stroke-width="4"
stroke-linecap="round"
stroke-linejoin="round" />
<circle cx="28.5"
cy="7.1"
r="6.5"
:fill="fillColor" />
<circle cx="39.2"
cy="-10"
r="6.5"
transform="rotate(90)"
:fill="fillColor" />
<circle cx="39.2"
cy="-47"
r="6.5"
transform="rotate(90)"
:fill="fillColor" />
<title v-if="title">{{ title }}</title>
</svg>
</span>
</template>
<script>
export default {
name: 'CirclesAppIcon',
props: {
title: {
type: String,
default: 'Circles',
},
fillColor: {
type: String,
default: 'currentColor',
},
size: {
type: Number,
default: 24,
},
},
}
</script>

Просмотреть файл

@ -0,0 +1,48 @@
<template>
<span :aria-hidden="!title"
:aria-label="title"
class="material-design-icon polls-maybe-icon"
role="img"
v-bind="$attrs"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 16 16">
<g id="open-brace"
style="font-style:normal;font-weight:normal;font-size:10.03817844px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffc10f;fill-opacity:0.94117647;stroke:none;stroke-width:0.6844213"
transform="matrix(1.2792345,0,0,1.0763308,-0.2918408,-1.3872412)"
aria-label="(">
<path id="path853" style="font-size:9.81086349px;fill:#ffc10f;fill-opacity:0.94117647;stroke-width:0.6844213" d="m 3.7425891,4.3526202 q -0.6419218,1.101806 -0.9533017,2.1796596 -0.31138,1.0778537 -0.31138,2.1844501 0,1.1065964 0.31138,2.1940311 0.3161704,1.082644 0.9533017,2.17966 H 2.9761153 Q 2.2575462,11.964662 1.8982617,10.877228 1.5437676,9.7897931 1.5437676,8.7167299 q 0,-1.0682727 0.3544941,-2.1509169 0.3544941,-1.0826441 1.0778536,-2.2131928 z" />
</g>
<path id="checkmark" d="M 4.2292965,7.4561992 6.8988209,10.399892 11.770704,5.0276561" style="fill:none;fill-opacity:1;stroke:#ffc10f;stroke-width:1.40162849;stroke-opacity:0.94117647" />
<g id="close-brace"
style="font-style:normal;font-weight:normal;font-size:10.03817844px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffc10f;fill-opacity:0.94117647;stroke:none;stroke-width:0.6844213"
transform="matrix(-1.2792345,0,0,-1.0763308,-2.4031246,-1.3872405)"
aria-label="(">
<path id="path856" style="font-size:9.81086349px;fill:#ffc10f;fill-opacity:0.94117647;stroke-width:0.6844213" d="m -10.871757,-13.09042 q -0.641921,1.101806 -0.953301,2.179659 -0.31138,1.0778541 -0.31138,2.1844505 0,1.1065964 0.31138,2.194031 0.31617,1.0826441 0.953301,2.1796596 h -0.766473 q -0.718569,-1.1257582 -1.077854,-2.2131928 -0.354494,-1.0874346 -0.354494,-2.1604978 0,-1.0682727 0.354494,-2.1509165 0.354494,-1.082644 1.077854,-2.213193 z" />
</g>
</svg>
</span>
</template>
<script>
export default {
name: 'MaybeIcon',
props: {
title: {
type: String,
default: 'Maybe',
},
fillColor: {
type: String,
default: '#ffc107',
},
size: {
type: Number,
default: 24,
},
},
}
</script>

Просмотреть файл

@ -0,0 +1,50 @@
<template>
<span :aria-hidden="!title"
:aria-label="title"
class="material-design-icon polls-app-icon"
role="img"
v-bind="$attrs"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 32 32">
<g :fill="fillColor">
<rect y="2"
x="3"
height="26"
width="7" />
<rect y="12"
x="12"
height="16"
width="7" />
<rect y="8"
x="21"
height="20"
width="7" />
<title v-if="title">{{ title }}</title>
</g>
</svg>
</span>
</template>
<script>
export default {
name: 'PollsAppIcon',
props: {
title: {
type: String,
default: 'Polls',
},
fillColor: {
type: String,
default: 'currentColor',
},
size: {
type: Number,
default: 24,
},
},
}
</script>

Просмотреть файл

@ -0,0 +1,38 @@
<template>
<span :aria-hidden="!title"
:aria-label="title"
class="material-design-icon publish-off-icon"
role="img"
v-bind="$attrs"
@click="$emit('click', $event)">
<svg :fill="fillColor"
class="material-design-icon__svg"
:width="size"
:height="size"
viewBox="0 0 24 24">
<path d="M20.8 22.7L15 16.9V20H9V14H5L8.6 10.4L1.1 3L2.4 1.7L22.1 21.4L20.8 22.7M19 6V4H7.2L9.2 6H19M17.2 14H19L12 7L11.1 7.9L17.2 14Z">
<title v-if="title">{{ title }}</title>
</path>
</svg>
</span>
</template>
<script>
export default {
name: 'PublishOff',
props: {
title: {
type: String,
default: 'Circles',
},
fillColor: {
type: String,
default: 'currentColor',
},
size: {
type: Number,
default: 24,
},
},
}
</script>

Просмотреть файл

@ -22,10 +22,9 @@
<template lang="html"> <template lang="html">
<Component :is="tag" class="badge"> <Component :is="tag" class="badge">
<div :class="icon" /> <div>
<span> <slot name="icon" />
{{ title }} </div>
</span>
<span> <span>
<slot /> <slot />
</span> </span>
@ -36,14 +35,6 @@
export default { export default {
name: 'Badge', name: 'Badge',
props: { props: {
title: {
type: String,
default: '',
},
icon: {
type: String,
default: '',
},
tag: { tag: {
type: String, type: String,
default: 'span', default: 'span',
@ -55,6 +46,7 @@ export default {
<style lang="scss"> <style lang="scss">
.badge { .badge {
display: flex; display: flex;
align-items: center;
gap: 5px; gap: 5px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: 5px; padding: 5px;
@ -73,18 +65,12 @@ export default {
border-color: var(--color-error); border-color: var(--color-error);
background-color: var(--color-error); background-color: var(--color-error);
color: var(--color-primary-text) !important; color: var(--color-primary-text) !important;
[class*='icon-mask-md-'] {
background-color: #fff;
}
} }
&.success { &.success {
border-color: var(--color-success); border-color: var(--color-success);
background-color: var(--color-success); background-color: var(--color-success);
color: var(--color-primary-text) !important; color: var(--color-primary-text) !important;
[class*='icon-mask-md-'] {
background-color: #fff;
}
} }
} }

Просмотреть файл

@ -21,7 +21,7 @@
--> -->
<template lang="html"> <template lang="html">
<Actions default-icon="icon-mask-md-export"> <Actions>
<template #icon> <template #icon>
<ExportIcon /> <ExportIcon />
</template> </template>

Просмотреть файл

@ -22,32 +22,43 @@
<template lang="html"> <template lang="html">
<AppNavigationItem :title="poll.title" <AppNavigationItem :title="poll.title"
:icon="pollTypeIcon"
:to="{name: 'vote', params: {id: poll.id}}" :to="{name: 'vote', params: {id: poll.id}}"
:class="{ closed: closed }"> :class="{ closed: closed }">
<template #icon>
<TextPollIcon v-if="poll.type === 'textPoll'" />
<DatePollIcon v-else />
</template>
<template #actions> <template #actions>
<ActionButton v-if="isPollCreationAllowed" <ActionButton v-if="isPollCreationAllowed"
icon="icon-mask-md-clone-poll"
@click="$emit('clone-poll')"> @click="$emit('clone-poll')">
<template #icon>
<ClonePollIcon />
</template>
{{ t('polls', 'Clone poll') }} {{ t('polls', 'Clone poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && !poll.deleted" <ActionButton v-if="poll.allowEdit && !poll.deleted"
icon="icon-mask-md-archive-poll"
@click="$emit('toggle-archive')"> @click="$emit('toggle-archive')">
<template #icon>
<ArchivePollIcon />
</template>
{{ t('polls', 'Archive poll') }} {{ t('polls', 'Archive poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && poll.deleted" <ActionButton v-if="poll.allowEdit && poll.deleted"
icon="icon-mask-md-restore-poll"
@click="$emit('toggle-archive')"> @click="$emit('toggle-archive')">
<template #icon>
<RestorePollIcon />
</template>
{{ t('polls', 'Restore poll') }} {{ t('polls', 'Restore poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && poll.deleted" <ActionButton v-if="poll.allowEdit && poll.deleted"
icon="icon-mask-md-delete-poll"
class="danger" class="danger"
@click="$emit('delete-poll')"> @click="$emit('delete-poll')">
<template #icon>
<DeletePollIcon />
</template>
{{ t('polls', 'Delete poll') }} {{ t('polls', 'Delete poll') }}
</ActionButton> </ActionButton>
</template> </template>
@ -58,6 +69,12 @@
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import { ActionButton, AppNavigationItem } from '@nextcloud/vue' import { ActionButton, AppNavigationItem } from '@nextcloud/vue'
import DeletePollIcon from 'vue-material-design-icons/Delete.vue'
import ClonePollIcon from 'vue-material-design-icons/ContentCopy.vue'
import ArchivePollIcon from 'vue-material-design-icons/Archive.vue'
import RestorePollIcon from 'vue-material-design-icons/Recycle.vue'
import TextPollIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
import DatePollIcon from 'vue-material-design-icons/CalendarBlank.vue'
export default { export default {
name: 'PollNavigationItems', name: 'PollNavigationItems',
@ -65,6 +82,12 @@ export default {
components: { components: {
ActionButton, ActionButton,
AppNavigationItem, AppNavigationItem,
DeletePollIcon,
ClonePollIcon,
ArchivePollIcon,
RestorePollIcon,
TextPollIcon,
DatePollIcon,
}, },
props: { props: {
@ -82,14 +105,6 @@ export default {
...mapGetters({ ...mapGetters({
closed: 'poll/isClosed', closed: 'poll/isClosed',
}), }),
pollTypeIcon() {
if (this.poll.type === 'textPoll') {
return 'icon-mask-md-text-poll'
}
return 'icon-mask-md-date-poll'
},
}, },
} }
</script> </script>

Просмотреть файл

@ -62,11 +62,16 @@
</OptionItem> </OptionItem>
</transition-group> </transition-group>
<EmptyContent v-else :icon="pollTypeIcon"> <EmptyContent v-else>
{{ t('polls', 'No vote options') }} <template #icon>
<DatePollIcon />
</template>
<template #desc> <template #desc>
{{ t('polls', 'Add some!') }} {{ t('polls', 'Add some!') }}
</template> </template>
{{ t('polls', 'No vote options') }}
</EmptyContent> </EmptyContent>
<Modal v-if="cloneModal" size="small" :can-close="false"> <Modal v-if="cloneModal" size="small" :can-close="false">
@ -86,6 +91,7 @@ import { dateUnits } from '../../mixins/dateMixins.js'
import CloneDateIcon from 'vue-material-design-icons/CalendarMultiple.vue' import CloneDateIcon from 'vue-material-design-icons/CalendarMultiple.vue'
import UnconfirmIcon from 'vue-material-design-icons/CheckboxMarkedOutline.vue' import UnconfirmIcon from 'vue-material-design-icons/CheckboxMarkedOutline.vue'
import ConfirmIcon from 'vue-material-design-icons/CheckboxBlankOutline.vue' import ConfirmIcon from 'vue-material-design-icons/CheckboxBlankOutline.vue'
import DatePollIcon from 'vue-material-design-icons/CalendarBlank.vue'
export default { export default {
name: 'OptionsDate', name: 'OptionsDate',
@ -102,6 +108,7 @@ export default {
OptionCloneDate, OptionCloneDate,
OptionItem, OptionItem,
VueButton, VueButton,
DatePollIcon,
OptionItemOwner: () => import('./OptionItemOwner.vue'), OptionItemOwner: () => import('./OptionItemOwner.vue'),
}, },
@ -129,7 +136,6 @@ export default {
...mapGetters({ ...mapGetters({
closed: 'poll/isClosed', closed: 'poll/isClosed',
countOptions: 'options/count', countOptions: 'options/count',
pollTypeIcon: 'poll/typeIcon',
}), }),
}, },

Просмотреть файл

@ -58,11 +58,16 @@
</transition-group> </transition-group>
</draggable> </draggable>
<EmptyContent v-else :icon="pollTypeIcon"> <EmptyContent v-else>
{{ t('polls', 'No vote options') }} <template #icon>
<TextPollIcon />
</template>
<template #desc> <template #desc>
{{ t('polls', 'Add some!') }} {{ t('polls', 'Add some!') }}
</template> </template>
{{ t('polls', 'No vote options') }}
</EmptyContent> </EmptyContent>
</div> </div>
</template> </template>
@ -77,6 +82,7 @@ import OptionItemOwner from '../Options/OptionItemOwner.vue'
import { confirmOption, removeOption } from '../../mixins/optionMixins.js' import { confirmOption, removeOption } from '../../mixins/optionMixins.js'
import UnconfirmIcon from 'vue-material-design-icons/CheckboxMarkedOutline.vue' import UnconfirmIcon from 'vue-material-design-icons/CheckboxMarkedOutline.vue'
import ConfirmIcon from 'vue-material-design-icons/CheckboxBlankOutline.vue' import ConfirmIcon from 'vue-material-design-icons/CheckboxBlankOutline.vue'
import TextPollIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
export default { export default {
name: 'OptionsText', name: 'OptionsText',
@ -90,6 +96,7 @@ export default {
OptionItem, OptionItem,
OptionItemOwner, OptionItemOwner,
VueButton, VueButton,
TextPollIcon,
OptionsTextAdd: () => import('./OptionsTextAdd.vue'), OptionsTextAdd: () => import('./OptionsTextAdd.vue'),
}, },
@ -115,7 +122,6 @@ export default {
...mapGetters({ ...mapGetters({
closed: 'poll/isClosed', closed: 'poll/isClosed',
countOptions: 'options/count', countOptions: 'options/count',
pollTypeIcon: 'poll/typeIcon',
}), }),
dragOptions() { dragOptions() {

Просмотреть файл

@ -23,7 +23,7 @@
<template lang="html"> <template lang="html">
<div class="poll-info-line"> <div class="poll-info-line">
<span v-for="(subText) in subTexts" :key="subText.id" :class="['sub-text', subText.class]"> <span v-for="(subText) in subTexts" :key="subText.id" :class="['sub-text', subText.class]">
<span :class="subText.icon" /> <Component :is="subText.iconComponent" :size="16" />
<span class="sub-text">{{ subText.text }}</span> <span class="sub-text">{{ subText.text }}</span>
</span> </span>
</div> </div>
@ -32,6 +32,12 @@
<script> <script>
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from '@nextcloud/moment' import moment from '@nextcloud/moment'
import unpublishedIcon from '../AppIcons/PublishOff.vue'
import archivedPollIcon from 'vue-material-design-icons/Archive.vue'
import closedPollIcon from 'vue-material-design-icons/Lock.vue'
import creationIcon from 'vue-material-design-icons/ClockOutline.vue'
import ProposalsIcon from 'vue-material-design-icons/Offer.vue'
import ExpirationIcon from 'vue-material-design-icons/CalendarEnd.vue'
export default { export default {
name: 'PollInfoLine', name: 'PollInfoLine',
@ -62,6 +68,16 @@ export default {
subTexts() { subTexts() {
const subTexts = [] const subTexts = []
if (this.isDeleted) {
subTexts.push({
id: 'deleted',
text: t('polls', 'Archived'),
class: 'archived',
iconComponent: archivedPollIcon,
})
return subTexts
}
if (this.isNoAccessSet) { if (this.isNoAccessSet) {
subTexts.push({ subTexts.push({
id: 'no-access', id: 'no-access',
@ -69,8 +85,8 @@ export default {
t('polls', 'This poll is unpublished'), t('polls', 'This poll is unpublished'),
t('polls', 'Invite users via the share tab in the sidebar'), t('polls', 'Invite users via the share tab in the sidebar'),
].join('. '), ].join('. '),
icon: 'icon-mask-md-unpublished-poll',
class: 'unpublished', class: 'unpublished',
iconComponent: unpublishedIcon,
}) })
return subTexts return subTexts
} }
@ -79,34 +95,24 @@ export default {
subTexts.push({ subTexts.push({
id: this.access, id: this.access,
text: t('polls', 'A private poll from {name}', { name: this.ownerDisplayName }), text: t('polls', 'A private poll from {name}', { name: this.ownerDisplayName }),
icon: '',
class: '', class: '',
iconComponent: null,
}) })
} else { } else {
subTexts.push({ subTexts.push({
id: this.access, id: this.access,
text: t('polls', 'An openly accessible poll from {name}', { name: this.ownerDisplayName }), text: t('polls', 'An openly accessible poll from {name}', { name: this.ownerDisplayName }),
icon: '',
class: '', class: '',
iconComponent: null,
}) })
} }
if (this.isDeleted) {
subTexts.push({
id: 'deleted',
text: t('polls', 'Archived'),
icon: 'icon-mask-md-archived-poll',
class: 'archived',
})
return subTexts
}
if (this.isClosed) { if (this.isClosed) {
subTexts.push({ subTexts.push({
id: 'closed', id: 'closed',
text: this.timeExpirationRelative, text: this.timeExpirationRelative,
icon: 'icon-mask-md-closed-poll',
class: 'closed', class: 'closed',
iconComponent: closedPollIcon,
}) })
return subTexts return subTexts
} }
@ -115,8 +121,8 @@ export default {
subTexts.push({ subTexts.push({
id: 'expiring', id: 'expiring',
text: t('polls', 'Closing {relativeExpirationTime}', { relativeExpirationTime: this.timeExpirationRelative }), text: t('polls', 'Closing {relativeExpirationTime}', { relativeExpirationTime: this.timeExpirationRelative }),
icon: 'icon-mask-md-expiration',
class: this.closeToClosing ? 'closing' : 'open', class: this.closeToClosing ? 'closing' : 'open',
iconComponent: ExpirationIcon,
}) })
return subTexts return subTexts
} }
@ -125,8 +131,8 @@ export default {
subTexts.push({ subTexts.push({
id: 'expired', id: 'expired',
text: t('polls', 'Proposal period ended {timeRelative}', { timeRelative: this.proposalsExpireRelative }), text: t('polls', 'Proposal period ended {timeRelative}', { timeRelative: this.proposalsExpireRelative }),
icon: 'icon-mask-md-proposals',
class: 'proposal', class: 'proposal',
iconComponent: ProposalsIcon,
}) })
return subTexts return subTexts
} }
@ -135,8 +141,8 @@ export default {
subTexts.push({ subTexts.push({
id: 'proposal-open', id: 'proposal-open',
text: t('polls', 'Proposal period ends {timeRelative}', { timeRelative: this.proposalsExpireRelative }), text: t('polls', 'Proposal period ends {timeRelative}', { timeRelative: this.proposalsExpireRelative }),
icon: 'icon-mask-md-proposals',
class: 'proposal', class: 'proposal',
iconComponent: ProposalsIcon,
}) })
return subTexts return subTexts
} }
@ -145,8 +151,8 @@ export default {
subTexts.push({ subTexts.push({
id: 'created', id: 'created',
text: this.dateCreatedRelative, text: this.dateCreatedRelative,
icon: 'icon-mask-md-creation',
class: 'created', class: 'created',
iconComponent: creationIcon,
}) })
} }
return subTexts return subTexts
@ -171,11 +177,6 @@ export default {
} }
</script> </script>
.poll-info-line [class^="icon-"], .poll-info-line [class*=" icon-"] {
/* padding-right: 21px; */
width: var(--icon-size);
margin: 0px 6px 0 2px;
}
<style lang="scss"> <style lang="scss">
.poll-info-line { .poll-info-line {
display: flex; display: flex;
@ -183,6 +184,10 @@ export default {
opacity: 0.7; opacity: 0.7;
font-size: 1em; font-size: 1em;
.material-design-icon {
padding: 0 2px;
}
.sub-text { .sub-text {
display: flex; display: flex;
} }
@ -192,25 +197,14 @@ export default {
padding: 0 2px; padding: 0 2px;
} }
[class^="icon-"], .closed, .archived {
[class*=" icon-"] {
width: var(--icon-size);
margin: 0px 6px 0 2px;
}
[class^="icon-md"],
[class*=" icon-md"] {
mask-size: var(--icon-size);
}
.closed {
.sub-text{ .sub-text{
color: var(--color-error); color: var(--color-error);
font-weight: 700; font-weight: 700;
} }
} }
.unpublished { .unpublished, .open {
.sub-text{ .sub-text{
font-weight: 700; font-weight: 700;
} }
@ -223,19 +217,6 @@ export default {
} }
} }
.open {
.sub-text{
font-weight: 700;
}
}
.archived {
.sub-text{
color: var(--color-error);
font-weight: 700;
}
}
.created { .created {
.sub-text{ .sub-text{
color: var(--color-text-light); color: var(--color-text-light);

Просмотреть файл

@ -22,46 +22,111 @@
<template lang="html"> <template lang="html">
<div class="poll-information"> <div class="poll-information">
<Badge icon="icon-mask-md-owner"> <Badge>
<template #icon>
<OwnerIcon />
</template>
{{ t('polls', 'Poll owner:') }} <UserBubble v-if="poll.owner.userId" :user="poll.owner.userId" :display-name="poll.owner.displayName" /> {{ t('polls', 'Poll owner:') }} <UserBubble v-if="poll.owner.userId" :user="poll.owner.userId" :display-name="poll.owner.displayName" />
</Badge> </Badge>
<Badge :icon="accessClass" :title="accessCaption" /> <Badge>
<Badge icon="icon-mask-md-creation" <template #icon>
:title="t('polls', 'Created {dateRelative}', { dateRelative: dateCreatedRelative })" /> <PrivatePollIcon v-if="access === 'private'" />
<Badge v-if="poll.expire" <OpenPollIcon v-else />
icon="icon-mask-md-closed-poll" </template>
:title="t('polls', 'Closing: {dateRelative}', {dateRelative: dateExpiryRelative})" /> {{ accessCaption }}
<Badge v-if="poll.anonymous" </Badge>
icon="icon-mask-md-anonymous-poll" <Badge>
:title="t('polls', 'Anonymous poll')" /> <template #icon>
<Badge :icon="resultsClass" :title="resultsCaption" /> <CreationIcon />
<Badge v-if="countParticipantsVoted && acl.allowSeeResults" </template>
icon="icon-mask-md-participants" {{ t('polls', 'Created {dateRelative}', { dateRelative: dateCreatedRelative }) }}
:title="n('polls', '%n Participant', '%n Participants', countParticipantsVoted)" /> </Badge>
<Badge icon="icon-mask-md-options" :title="n('polls', '%n option', '%n options', countOptions)" /> <Badge v-if="poll.expire">
<Badge v-if="countAllYesVotes" icon="icon-mask-md-yes-votes"> <template #icon>
<ClosedIcon />
</template>
{{ t('polls', 'Closing: {dateRelative}', {dateRelative: dateExpiryRelative}) }}
</Badge>
<Badge v-if="poll.anonymous">
<template #icon>
<AnoymousIcon />
</template>
{{ t('polls', 'Anonymous poll') }}
</Badge>
<Badge>
<template #icon>
<HideResultsIcon v-if="showResults === 'never'" />
<ShowResultsOnClosedIcon v-else-if="showResults === 'closed' && closed" />
<ShowResultsIcon v-else />
</template>
{{ resultsCaption }}
</Badge>
<Badge v-if="countParticipantsVoted && acl.allowSeeResults">
<template #icon>
<ParticipantsIcon />
</template>
{{ n('polls', '%n Participant', '%n Participants', countParticipantsVoted) }}
</Badge>
<Badge>
<template #icon>
<OptionsIcon />
</template>
{{ n('polls', '%n option', '%n options', countOptions) }}
</Badge>
<Badge v-if="countAllYesVotes">
<template #icon>
<CheckIcon fill-color="#49bc49" />
</template>
{{ n('polls', '%n "Yes" vote', '%n "Yes" votes', countAllYesVotes) }} {{ n('polls', '%n "Yes" vote', '%n "Yes" votes', countAllYesVotes) }}
</Badge> </Badge>
<Badge v-if="countAllNoVotes" icon="icon-mask-md-no-votes"> <Badge v-if="countAllNoVotes">
<template #icon>
<CloseIcon fill-color="#f45573" />
</template>
{{ n('polls', '%n No vote', '%n "No" votes', countAllNoVotes) }} {{ n('polls', '%n No vote', '%n "No" votes', countAllNoVotes) }}
</Badge> </Badge>
<Badge v-if="countAllMaybeVotes" icon="icon-mask-md-maybe-votes"> <Badge v-if="countAllMaybeVotes">
<template #icon>
<MaybeIcon />
</template>
{{ n('polls', '%n "Maybe" vote', '%n "Maybe" votes', countAllMaybeVotes) }} {{ n('polls', '%n "Maybe" vote', '%n "Maybe" votes', countAllMaybeVotes) }}
</Badge> </Badge>
<Badge icon="icon-mask-md-timezone" :title="t('polls', 'Time zone: {timezoneString}', { timezoneString: currentTimeZone})" /> <Badge>
<Badge v-if="proposalsAllowed" icon="icon-mask-md-proposals-allowed" :title="proposalsStatus" /> <template #icon>
<div v-if="poll.voteLimit" class="icon-checkmark"> <TimezoneIcon />
</template>
{{ t('polls', 'Time zone: {timezoneString}', { timezoneString: currentTimeZone}) }}
</Badge>
<Badge v-if="proposalsAllowed">
<template #icon>
<ProposalsAllowedIcon />
</template>
{{ proposalsStatus }}
</Badge>
<Badge v-if="poll.voteLimit">
<template #icon>
<CheckIcon />
</template>
{{ n('polls', '%n of {maximalVotes} vote left.', '%n of {maximalVotes} votes left.', poll.voteLimit - countVotes('yes'), { maximalVotes: poll.voteLimit }) }} {{ n('polls', '%n of {maximalVotes} vote left.', '%n of {maximalVotes} votes left.', poll.voteLimit - countVotes('yes'), { maximalVotes: poll.voteLimit }) }}
</div> </Badge>
<div v-if="poll.optionLimit" class="icon-close"> <Badge v-if="poll.optionLimit">
<template #icon>
<CloseIcon />
</template>
{{ n('polls', 'Only %n vote per option.', 'Only %n votes per option.', poll.optionLimit) }} {{ n('polls', 'Only %n vote per option.', 'Only %n votes per option.', poll.optionLimit) }}
</div> </Badge>
<div v-if="$route.name === 'publicVote' && share.emailAddress" class="icon-mail"> <Badge v-if="$route.name === 'publicVote' && share.emailAddress">
<template #icon>
<EmailIcon />
</template>
{{ share.emailAddress }} {{ share.emailAddress }}
</div> </Badge>
<Badge v-if="subscribed" <Badge v-if="subscribed">
icon="icon-mask-md-subscribed" <template #icon>
:title="t('polls', 'You subscribed to this poll')" /> <SubscribedIcon />
</template>
{{ t('polls', 'You subscribed to this poll') }}
</Badge>
</div> </div>
</template> </template>
@ -70,6 +135,24 @@ import { mapState, mapGetters } from 'vuex'
import moment from '@nextcloud/moment' import moment from '@nextcloud/moment'
import { UserBubble } from '@nextcloud/vue' import { UserBubble } from '@nextcloud/vue'
import Badge from '../Base/Badge.vue' import Badge from '../Base/Badge.vue'
import OwnerIcon from 'vue-material-design-icons/Crown.vue'
import SubscribedIcon from 'vue-material-design-icons/Bell.vue'
import ProposalsAllowedIcon from 'vue-material-design-icons/Offer.vue'
import TimezoneIcon from 'vue-material-design-icons/MapClockOutline.vue'
import OptionsIcon from 'vue-material-design-icons/FormatListCheckbox.vue'
import ParticipantsIcon from 'vue-material-design-icons/AccountGroup.vue'
import ShowResultsIcon from 'vue-material-design-icons/Monitor.vue'
import ShowResultsOnClosedIcon from 'vue-material-design-icons/MonitorLock.vue'
import HideResultsIcon from 'vue-material-design-icons/MonitorOff.vue'
import AnoymousIcon from 'vue-material-design-icons/Incognito.vue'
import ClosedIcon from 'vue-material-design-icons/Lock.vue'
import CreationIcon from 'vue-material-design-icons/ClockOutline.vue'
import PrivatePollIcon from 'vue-material-design-icons/Key.vue'
import OpenPollIcon from 'vue-material-design-icons/Earth.vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import CloseIcon from 'vue-material-design-icons/Close.vue'
import EmailIcon from 'vue-material-design-icons/Email.vue'
import MaybeIcon from '../AppIcons/MaybeIcon.vue'
export default { export default {
name: 'PollInformation', name: 'PollInformation',
@ -77,6 +160,24 @@ export default {
components: { components: {
Badge, Badge,
UserBubble, UserBubble,
OwnerIcon,
SubscribedIcon,
ProposalsAllowedIcon,
TimezoneIcon,
OptionsIcon,
ParticipantsIcon,
ShowResultsIcon,
ShowResultsOnClosedIcon,
HideResultsIcon,
AnoymousIcon,
ClosedIcon,
CreationIcon,
PrivatePollIcon,
OpenPollIcon,
CheckIcon,
CloseIcon,
MaybeIcon,
EmailIcon,
}, },
computed: { computed: {
@ -131,17 +232,6 @@ export default {
return t('polls', 'Results are visible') return t('polls', 'Results are visible')
}, },
resultsClass() {
if (this.showResults === 'never') {
return 'icon-mask-md-show-results-never'
}
if (this.showResults === 'closed' && !this.closed) {
return 'icon-mask-md-hide-results-until-closed'
}
return 'icon-mask-md-show-results'
},
accessCaption() { accessCaption() {
if (this.access === 'private') { if (this.access === 'private') {
return t('polls', 'Private poll') return t('polls', 'Private poll')
@ -152,16 +242,6 @@ export default {
return t('polls', 'Openly accessible poll') return t('polls', 'Openly accessible poll')
}, },
accessClass() {
if (this.access === 'private') {
return 'icon-mask-md-private-poll'
}
if (this.important) {
return 'icon-mask-md-open-poll'
}
return 'icon-mask-md-open-poll'
},
dateCreatedRelative() { dateCreatedRelative() {
return moment.unix(this.poll.created).fromNow() return moment.unix(this.poll.created).fromNow()
}, },

Просмотреть файл

@ -53,7 +53,11 @@
</div> </div>
<div v-else class="poll-item__item"> <div v-else class="poll-item__item">
<div v-tooltip.auto="pollTypeName" :class="['item__icon-spacer', pollTypeIcon]" /> <div v-tooltip.auto="pollTypeName" class="item__icon-spacer">
<TextPollIcon v-if="pollType === 'textPoll'" />
<DatePollIcon v-else />
</div>
<!-- <div v-tooltip.auto="pollTypeName" :class="['item__icon-spacer', pollTypeIcon]" /> -->
<div v-if="noLink" class="item__title" :class="{ closed: closed }"> <div v-if="noLink" class="item__title" :class="{ closed: closed }">
<div class="item__title__title"> <div class="item__title__title">
@ -79,8 +83,11 @@
</router-link> </router-link>
<slot name="actions" /> <slot name="actions" />
<div v-tooltip.auto="accessType" class="item__access">
<div v-tooltip.auto="accessType" :class="['item__access', accessIcon]" /> <ArchivedPollIcon v-if="poll.deleted" />
<OpenPollIcon v-else-if="poll.access === 'open'" />
<PrivatePollIcon v-else />
</div>
<div class="item__owner"> <div class="item__owner">
<UserItem v-bind="poll.owner" condensed /> <UserItem v-bind="poll.owner" condensed />
@ -88,13 +95,20 @@
<div class="wrapper"> <div class="wrapper">
<div class="item__created"> <div class="item__created">
<Badge :title="timeCreatedRelative" <Badge>
icon="icon-mask-md-creation" /> <template #icon>
<CreationIcon />
</template>
{{ timeCreatedRelative }}
</Badge>
</div> </div>
<div class="item__expiry"> <div class="item__expiry">
<Badge :title="timeExpirationRelative" <Badge :class="expiryClass">
icon="icon-mask-md-expiration" <template #icon>
:class="expiryClass" /> <ExpirationIcon />
</template>
{{ timeExpirationRelative }}
</Badge>
</div> </div>
</div> </div>
</div> </div>
@ -104,11 +118,25 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import moment from '@nextcloud/moment' import moment from '@nextcloud/moment'
import Badge from '../Base/Badge.vue' import Badge from '../Base/Badge.vue'
import TextPollIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
import DatePollIcon from 'vue-material-design-icons/CalendarBlank.vue'
import CreationIcon from 'vue-material-design-icons/ClockOutline.vue'
import ExpirationIcon from 'vue-material-design-icons/CalendarEnd.vue'
import PrivatePollIcon from 'vue-material-design-icons/Key.vue'
import OpenPollIcon from 'vue-material-design-icons/Earth.vue'
import ArchivedPollIcon from 'vue-material-design-icons/Archive.vue'
export default { export default {
name: 'PollItem', name: 'PollItem',
components: { components: {
Badge, Badge,
TextPollIcon,
DatePollIcon,
CreationIcon,
ExpirationIcon,
PrivatePollIcon,
OpenPollIcon,
ArchivedPollIcon,
}, },
props: { props: {
@ -152,34 +180,17 @@ export default {
return t('polls', 'Private poll') return t('polls', 'Private poll')
}, },
pollType() {
return this.poll.type
},
pollTypeName() { pollTypeName() {
if (this.poll.type === 'textPoll') { if (this.pollType === 'textPoll') {
return t('polls', 'Text poll') return t('polls', 'Text poll')
} }
return t('polls', 'Date poll') return t('polls', 'Date poll')
}, },
pollTypeIcon() {
if (this.poll.type === 'textPoll') {
return 'icon-mask-md-text-poll'
}
return 'icon-mask-md-date-poll'
},
accessIcon() {
if (this.poll.deleted) {
return 'icon-mask-md-archived-poll'
}
if (this.poll.access === 'open') {
return 'icon-mask-md-open-poll'
}
return 'icon-mask-md-private-poll'
},
timeExpirationRelative() { timeExpirationRelative() {
if (this.poll.expire) { if (this.poll.expire) {
return moment.unix(this.poll.expire).fromNow() return moment.unix(this.poll.expire).fromNow()

Просмотреть файл

@ -24,8 +24,11 @@
<div class="comments"> <div class="comments">
<CommentAdd v-if="acl.allowComment" /> <CommentAdd v-if="acl.allowComment" />
<Comments v-if="!showEmptyContent" /> <Comments v-if="!showEmptyContent" />
<EmptyContent v-else icon="icon-mask-md-sidebar-comments"> <EmptyContent v-else>
{{ t('polls', 'No comments') }} {{ t('polls', 'No comments') }}
<template #icon>
<CommentsIcon />
</template>
<template #desc> <template #desc>
{{ t('polls', 'Be the first.') }} {{ t('polls', 'Be the first.') }}
</template> </template>
@ -38,6 +41,7 @@ import CommentAdd from '../Comments/CommentAdd.vue'
import Comments from '../Comments/Comments.vue' import Comments from '../Comments/Comments.vue'
import { EmptyContent } from '@nextcloud/vue' import { EmptyContent } from '@nextcloud/vue'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import CommentsIcon from 'vue-material-design-icons/CommentProcessing.vue'
export default { export default {
name: 'SideBarTabComments', name: 'SideBarTabComments',
@ -45,6 +49,7 @@ export default {
CommentAdd, CommentAdd,
Comments, Comments,
EmptyContent, EmptyContent,
CommentsIcon,
}, },
computed: { computed: {

Просмотреть файл

@ -99,7 +99,6 @@ export default {
...mapGetters({ ...mapGetters({
closed: 'poll/isClosed', closed: 'poll/isClosed',
countOptions: 'options/count', countOptions: 'options/count',
pollTypeIcon: 'poll/typeIcon',
}), }),
...mapState({ ...mapState({
pollType: (state) => state.poll.type, pollType: (state) => state.poll.type,

Просмотреть файл

@ -21,25 +21,32 @@
--> -->
<template> <template>
<Actions default-icon="icon-settings" primary> <Actions primary>
<template #icon>
<SettingsIcon :size="20" decorative />
</template>
<ActionButton v-if="$route.name === 'publicVote'" icon="icon-md-link" @click="copyLink()"> <ActionButton v-if="$route.name === 'publicVote'" icon="icon-md-link" @click="copyLink()">
{{ t('polls', 'Copy your personal link to clipboard') }} {{ t('polls', 'Copy your personal link to clipboard') }}
</ActionButton> </ActionButton>
<ActionSeparator /> <ActionSeparator />
<ActionInput v-if="$route.name === 'publicVote'" <ActionInput v-if="$route.name === 'publicVote'"
icon="icon-mask-md-edit-email-address"
:class="check.status" :class="check.status"
:value="emailAddressTemp" :value="emailAddressTemp"
@click="deleteEmailAddress" @click="deleteEmailAddress"
@update:value="validateEmailAddress" @update:value="validateEmailAddress"
@submit="submitEmailAddress"> @submit="submitEmailAddress">
<template #icon>
<EditEmailIcon />
</template>
{{ t('polls', 'Edit Email Address') }} {{ t('polls', 'Edit Email Address') }}
</ActionInput> </ActionInput>
<ActionButton v-if="$route.name === 'publicVote'" <ActionButton v-if="$route.name === 'publicVote'"
:disabled="!emailAddress" :disabled="!emailAddress"
:value="emailAddress" :value="emailAddress"
icon="icon-mask-md-send-link-per-email"
@click="resendInvitation()"> @click="resendInvitation()">
<template #icon>
<SendLinkPerEmailIcon />
</template>
{{ t('polls', 'Get your personal link per mail') }} {{ t('polls', 'Get your personal link per mail') }}
</ActionButton> </ActionButton>
<ActionCheckbox :checked="subscribed" <ActionCheckbox :checked="subscribed"
@ -50,14 +57,22 @@
</ActionCheckbox> </ActionCheckbox>
<ActionButton v-if="$route.name === 'publicVote' && emailAddress" <ActionButton v-if="$route.name === 'publicVote' && emailAddress"
:disabled="!emailAddress" :disabled="!emailAddress"
icon="icon-mask-md-delete"
@click="deleteEmailAddress"> @click="deleteEmailAddress">
<template #icon>
<DeleteIcon />
</template>
{{ t('polls', 'Remove Email Address') }} {{ t('polls', 'Remove Email Address') }}
</ActionButton> </ActionButton>
<ActionButton v-if="acl.allowEdit" icon="icon-mask-md-clippy" @click="getAddresses()"> <ActionButton v-if="acl.allowEdit" @click="getAddresses()">
<template #icon>
<ClippyIcon />
</template>
{{ t('polls', 'Copy list of email addresses to clipboard') }} {{ t('polls', 'Copy list of email addresses to clipboard') }}
</ActionButton> </ActionButton>
<ActionButton icon="icon-mask-md-reset-votes" @click="resetVotes()"> <ActionButton @click="resetVotes()">
<template #icon>
<ResetVotesIcon />
</template>
{{ t('polls', 'Reset your votes') }} {{ t('polls', 'Reset your votes') }}
</ActionButton> </ActionButton>
</Actions> </Actions>
@ -70,6 +85,12 @@ import { showSuccess, showError } from '@nextcloud/dialogs'
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import { Actions, ActionButton, ActionCheckbox, ActionInput, ActionSeparator } from '@nextcloud/vue' import { Actions, ActionButton, ActionCheckbox, ActionInput, ActionSeparator } from '@nextcloud/vue'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import SettingsIcon from 'vue-material-design-icons/Cog.vue'
import EditEmailIcon from 'vue-material-design-icons/EmailEditOutline.vue'
import SendLinkPerEmailIcon from 'vue-material-design-icons/LinkVariant.vue'
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
import ClippyIcon from 'vue-material-design-icons/ClipboardArrowLeftOutline.vue'
import ResetVotesIcon from 'vue-material-design-icons/Undo.vue'
export default { export default {
name: 'UserMenu', name: 'UserMenu',
@ -80,6 +101,12 @@ export default {
ActionCheckbox, ActionCheckbox,
ActionInput, ActionInput,
ActionSeparator, ActionSeparator,
SettingsIcon,
EditEmailIcon,
SendLinkPerEmailIcon,
DeleteIcon,
ClippyIcon,
ResetVotesIcon,
}, },
data() { data() {

Просмотреть файл

@ -109,13 +109,6 @@ const getters = {
return t('polls', 'Date poll') return t('polls', 'Date poll')
}, },
typeIcon: (state) => {
if (state.type === 'textPoll') {
return 'icon-mask-md-text-poll'
}
return 'icon-mask-md-date-poll'
},
answerSequence: (state, getters, rootState) => { answerSequence: (state, getters, rootState) => {
const noString = rootState.poll.useNo ? 'no' : '' const noString = rootState.poll.useNo ? 'no' : ''
if (state.allowMaybe) { if (state.allowMaybe) {

Просмотреть файл

@ -43,7 +43,6 @@ const state = {
title: t('polls', 'Relevant'), title: t('polls', 'Relevant'),
titleExt: t('polls', 'Relevant polls'), titleExt: t('polls', 'Relevant polls'),
description: t('polls', 'All polls which are relevant or important to you, because you are a participant or the owner or you are invited to. Without polls closed more than five days ago.'), description: t('polls', 'All polls which are relevant or important to you, because you are a participant or the owner or you are invited to. Without polls closed more than five days ago.'),
icon: 'icon-mask-md-navigation-relevant',
pinned: false, pinned: false,
createDependent: false, createDependent: false,
filterCondition(poll) { filterCondition(poll) {
@ -61,7 +60,6 @@ const state = {
title: t('polls', 'My polls'), title: t('polls', 'My polls'),
titleExt: t('polls', 'My polls'), titleExt: t('polls', 'My polls'),
description: t('polls', 'Your polls (in which you are the owner).'), description: t('polls', 'Your polls (in which you are the owner).'),
icon: 'icon-mask-md-navigation-my',
pinned: false, pinned: false,
createDependent: true, createDependent: true,
filterCondition(poll) { filterCondition(poll) {
@ -73,7 +71,6 @@ const state = {
title: t('polls', 'Private polls'), title: t('polls', 'Private polls'),
titleExt: t('polls', 'Private polls'), titleExt: t('polls', 'Private polls'),
description: t('polls', 'All private polls, to which you have access.'), description: t('polls', 'All private polls, to which you have access.'),
icon: 'icon-mask-md-navigation-private',
pinned: false, pinned: false,
createDependent: true, createDependent: true,
filterCondition(poll) { filterCondition(poll) {
@ -85,7 +82,6 @@ const state = {
title: t('polls', 'Participated'), title: t('polls', 'Participated'),
titleExt: t('polls', 'Participated'), titleExt: t('polls', 'Participated'),
description: t('polls', 'All polls, where you placed a vote.'), description: t('polls', 'All polls, where you placed a vote.'),
icon: 'icon-mask-md-navigation-participated',
pinned: false, pinned: false,
createDependent: false, createDependent: false,
filterCondition(poll) { filterCondition(poll) {
@ -97,7 +93,6 @@ const state = {
title: t('polls', 'Openly accessible polls'), title: t('polls', 'Openly accessible polls'),
titleExt: t('polls', 'Openly accessible polls'), titleExt: t('polls', 'Openly accessible polls'),
description: t('polls', 'A complete list with all openly accessible polls on this site, regardless who is the owner.'), description: t('polls', 'A complete list with all openly accessible polls on this site, regardless who is the owner.'),
icon: 'icon-mask-md-navigation-open',
pinned: false, pinned: false,
createDependent: true, createDependent: true,
filterCondition(poll) { filterCondition(poll) {
@ -109,7 +104,6 @@ const state = {
title: t('polls', 'All polls'), title: t('polls', 'All polls'),
titleExt: t('polls', 'All polls'), titleExt: t('polls', 'All polls'),
description: t('polls', 'All polls, where you have access to.'), description: t('polls', 'All polls, where you have access to.'),
icon: 'icon-mask-md-navigation-all',
pinned: false, pinned: false,
createDependent: false, createDependent: false,
filterCondition(poll) { filterCondition(poll) {
@ -121,7 +115,6 @@ const state = {
title: t('polls', 'Closed polls'), title: t('polls', 'Closed polls'),
titleExt: t('polls', 'Closed polls'), titleExt: t('polls', 'Closed polls'),
description: t('polls', 'All closed polls, where voting is disabled.'), description: t('polls', 'All closed polls, where voting is disabled.'),
icon: 'icon-mask-md-navigation-closed',
pinned: false, pinned: false,
createDependent: false, createDependent: false,
filterCondition(poll) { filterCondition(poll) {
@ -135,7 +128,6 @@ const state = {
title: t('polls', 'Archive'), title: t('polls', 'Archive'),
titleExt: t('polls', 'My archived polls'), titleExt: t('polls', 'My archived polls'),
description: t('polls', 'Your archived polls are only accessible to you.'), description: t('polls', 'Your archived polls are only accessible to you.'),
icon: 'icon-mask-md-navigation-archived',
pinned: true, pinned: true,
createDependent: true, createDependent: true,
filterCondition(poll) { filterCondition(poll) {

Просмотреть файл

@ -59,7 +59,7 @@ const mutations = {
} }
const getters = { const getters = {
relevant: (state, getters, rootState) => state.list.filter((vote) => rootState.options.list.some((option) => option.pollId === vote.pollId && option.text === vote.voteOptionText)), relevant: (state, getters, rootState) => state.list.filter((vote) => rootState.options.list.some((option) => option.pollId === vote.pollId && option.text === vote.optionText)),
countVotes: (state, getters, rootState) => (answer) => getters.relevant.filter((vote) => vote.user.userId === rootState.poll.acl.userId && vote.answer === answer).length, countVotes: (state, getters, rootState) => (answer) => getters.relevant.filter((vote) => vote.user.userId === rootState.poll.acl.userId && vote.answer === answer).length,
countAllVotes: (state, getters) => (answer) => getters.relevant.filter((vote) => vote.answer === answer).length, countAllVotes: (state, getters) => (answer) => getters.relevant.filter((vote) => vote.answer === answer).length,
hasVoted: (state) => (userId) => state.list.findIndex((vote) => vote.user.userId === userId) > -1, hasVoted: (state) => (userId) => state.list.findIndex((vote) => vote.user.userId === userId) > -1,

Просмотреть файл

@ -27,15 +27,18 @@
:text="t('polls', 'Add new Poll')" :text="t('polls', 'Add new Poll')"
@click="toggleCreateDlg" /> @click="toggleCreateDlg" />
<CreateDlg v-show="createDlg" ref="createDlg" @close-create="closeCreate()" /> <CreateDlg v-show="createDlg" ref="createDlg" @close-create="closeCreate()" />
<template #list> <template #list>
<AppNavigationItem v-for="(pollCategory) in pollCategories" <AppNavigationItem v-for="(pollCategory) in pollCategories"
:key="pollCategory.id" :key="pollCategory.id"
:title="pollCategory.title" :title="pollCategory.title"
:allow-collapse="true" :allow-collapse="true"
:pinned="pollCategory.pinned" :pinned="pollCategory.pinned"
:icon="pollCategory.icon"
:to="{ name: 'list', params: {type: pollCategory.id}}" :to="{ name: 'list', params: {type: pollCategory.id}}"
:open="false"> :open="false">
<template #icon>
<Component :is="getIconComponent(pollCategory.id)" :size="iconSize" />
</template>
<ul> <ul>
<PollNavigationItems v-for="(poll) in filteredPolls(pollCategory.id)" <PollNavigationItems v-for="(poll) in filteredPolls(pollCategory.id)"
:key="poll.id" :key="poll.id"
@ -46,16 +49,28 @@
</ul> </ul>
</AppNavigationItem> </AppNavigationItem>
</template> </template>
<template #footer> <template #footer>
<AppNavigationItem v-if="isComboActivated" <AppNavigationItem v-if="isComboActivated"
:title="t('polls', 'Combine polls')" :title="t('polls', 'Combine polls')"
icon="icon-mask-md-navigation-combo" :to="{ name: 'combo' }">
:to="{ name: 'combo' }" /> <template #icon>
<ComboIcon :size="iconSize" />
</template>
</AppNavigationItem>
<AppNavigationItem v-if="showAdminSection" <AppNavigationItem v-if="showAdminSection"
:title="t('polls', 'Administration')" :title="t('polls', 'Administration')"
icon="icon-mask-md-navigation-administration" :to="{ name: 'administration' }">
:to="{ name: 'administration' }" /> <template #icon>
<AppNavigationItem :title="t('polls', 'Personal settings')" icon="icon-mask-md-navigation-personal-settings" @click="showSettings()" /> <AdministrationIcon :size="iconSize" />
</template>
</AppNavigationItem>
<AppNavigationItem :title="t('polls', 'Personal settings')"
@click="showSettings()">
<template #icon>
<SettingsIcon :size="iconSize" />
</template>
</AppNavigationItem>
</template> </template>
</AppNavigation> </AppNavigation>
</template> </template>
@ -69,6 +84,17 @@ import { showError } from '@nextcloud/dialogs'
import { emit } from '@nextcloud/event-bus' import { emit } from '@nextcloud/event-bus'
import CreateDlg from '../components/Create/CreateDlg.vue' import CreateDlg from '../components/Create/CreateDlg.vue'
import PollNavigationItems from '../components/Navigation/PollNavigationItems.vue' import PollNavigationItems from '../components/Navigation/PollNavigationItems.vue'
import ComboIcon from 'vue-material-design-icons/VectorCombine.vue'
import AdministrationIcon from 'vue-material-design-icons/Cog.vue'
import SettingsIcon from 'vue-material-design-icons/AccountCog.vue'
import RelevantIcon from 'vue-material-design-icons/ExclamationThick.vue'
import MyPollsIcon from 'vue-material-design-icons/Crown.vue'
import PrivatePollsIcon from 'vue-material-design-icons/Key.vue'
import ParticipatedIcon from 'vue-material-design-icons/AccountCheck.vue'
import OpenPollIcon from 'vue-material-design-icons/Earth.vue'
import AllPollsIcon from 'vue-material-design-icons/Poll.vue'
import ClosedPollsIcon from 'vue-material-design-icons/Lock.vue'
import ArchivedPollsIcon from 'vue-material-design-icons/Archive.vue'
export default { export default {
name: 'Navigation', name: 'Navigation',
@ -78,11 +104,25 @@ export default {
AppNavigationItem, AppNavigationItem,
CreateDlg, CreateDlg,
PollNavigationItems, PollNavigationItems,
ComboIcon,
SettingsIcon,
AdministrationIcon,
}, },
data() { data() {
return { return {
iconSize: 20,
createDlg: false, createDlg: false,
icons: [
{ id: 'relevant', iconComponent: RelevantIcon },
{ id: 'my', iconComponent: MyPollsIcon },
{ id: 'private', iconComponent: PrivatePollsIcon },
{ id: 'participated', iconComponent: ParticipatedIcon },
{ id: 'open', iconComponent: OpenPollIcon },
{ id: 'all', iconComponent: AllPollsIcon },
{ id: 'closed', iconComponent: ClosedPollsIcon },
{ id: 'archived', iconComponent: ArchivedPollsIcon },
],
} }
}, },
@ -115,6 +155,10 @@ export default {
this.createDlg = false this.createDlg = false
}, },
getIconComponent(iconId) {
return this.icons.find((icon) => icon.id === iconId).iconComponent
},
toggleCreateDlg() { toggleCreateDlg() {
this.createDlg = !this.createDlg this.createDlg = !this.createDlg
if (this.createDlg) { if (this.createDlg) {

Просмотреть файл

@ -53,31 +53,39 @@
<template #actions> <template #actions>
<Actions force-menu> <Actions force-menu>
<ActionButton v-if="isPollCreationAllowed" <ActionButton v-if="isPollCreationAllowed"
icon="icon-mask-md-clone-poll"
:close-after-click="true" :close-after-click="true"
@click="clonePoll(poll.id)"> @click="clonePoll(poll.id)">
<template #icon>
<ClonePollIcon />
</template>
{{ t('polls', 'Clone poll') }} {{ t('polls', 'Clone poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && !poll.deleted" <ActionButton v-if="poll.allowEdit && !poll.deleted"
icon="icon-mask-md-archive-poll"
:close-after-click="true" :close-after-click="true"
@click="toggleArchive(poll.id)"> @click="toggleArchive(poll.id)">
<template #icon>
<ArchivePollIcon />
</template>
{{ t('polls', 'Archive poll') }} {{ t('polls', 'Archive poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && poll.deleted" <ActionButton v-if="poll.allowEdit && poll.deleted"
icon="icon-mask-md-restore-poll"
:close-after-click="true" :close-after-click="true"
@click="toggleArchive(poll.id)"> @click="toggleArchive(poll.id)">
<template #icon>
<RestorePollIcon />
</template>
{{ t('polls', 'Restore poll') }} {{ t('polls', 'Restore poll') }}
</ActionButton> </ActionButton>
<ActionButton v-if="poll.allowEdit && poll.deleted" <ActionButton v-if="poll.allowEdit && poll.deleted"
icon="icon-mask-md-delete-poll"
class="danger" class="danger"
:close-after-click="true" :close-after-click="true"
@click="deletePoll(poll.id)"> @click="deletePoll(poll.id)">
<template #icon>
<DeletePollIcon />
</template>
{{ t('polls', 'Delete poll') }} {{ t('polls', 'Delete poll') }}
</ActionButton> </ActionButton>
</Actions> </Actions>
@ -95,6 +103,10 @@ import { showError } from '@nextcloud/dialogs'
import { emit } from '@nextcloud/event-bus' import { emit } from '@nextcloud/event-bus'
import { Actions, ActionButton, AppContent, EmptyContent } from '@nextcloud/vue' import { Actions, ActionButton, AppContent, EmptyContent } from '@nextcloud/vue'
import HeaderBar from '../components/Base/HeaderBar.vue' import HeaderBar from '../components/Base/HeaderBar.vue'
import DeletePollIcon from 'vue-material-design-icons/Delete.vue'
import ClonePollIcon from 'vue-material-design-icons/ContentCopy.vue'
import ArchivePollIcon from 'vue-material-design-icons/Archive.vue'
import RestorePollIcon from 'vue-material-design-icons/Recycle.vue'
export default { export default {
name: 'PollList', name: 'PollList',
@ -105,6 +117,10 @@ export default {
ActionButton, ActionButton,
EmptyContent, EmptyContent,
HeaderBar, HeaderBar,
DeletePollIcon,
ClonePollIcon,
ArchivePollIcon,
RestorePollIcon,
LoadingOverlay: () => import('../components/Base/LoadingOverlay.vue'), LoadingOverlay: () => import('../components/Base/LoadingOverlay.vue'),
PollItem: () => import('../components/PollList/PollItem.vue'), PollItem: () => import('../components/PollList/PollItem.vue'),
}, },

Просмотреть файл

@ -28,24 +28,30 @@
<AppSidebarTab v-if="acl.allowEdit" <AppSidebarTab v-if="acl.allowEdit"
:id="'configuration'" :id="'configuration'"
:order="1" :order="1"
:name="t('polls', 'Configuration')" :name="t('polls', 'Configuration')">
icon="icon-mask-md-sidebar-configuration"> <template #icon>
<SidebarConfigurationIcon />
</template>
<SideBarTabConfiguration /> <SideBarTabConfiguration />
</AppSidebarTab> </AppSidebarTab>
<AppSidebarTab v-if="acl.allowEdit" <AppSidebarTab v-if="acl.allowEdit"
:id="'options'" :id="'options'"
:order="2" :order="2"
:name="t('polls', 'Options')" :name="t('polls', 'Options')">
icon="icon-mask-md-sidebar-options"> <template #icon>
<SidebarOptionsIcon />
</template>
<SideBarTabOptions /> <SideBarTabOptions />
</AppSidebarTab> </AppSidebarTab>
<AppSidebarTab v-if="acl.allowEdit" <AppSidebarTab v-if="acl.allowEdit"
:id="'sharing'" :id="'sharing'"
:order="3" :order="3"
:name="t('polls', 'Sharing')" :name="t('polls', 'Sharing')">
icon="icon-mask-md-sidebar-share"> <template #icon>
<SidebarShareIcon />
</template>
<SideBarTabShare /> <SideBarTabShare />
</AppSidebarTab> </AppSidebarTab>
@ -60,8 +66,10 @@
<AppSidebarTab v-if="acl.allowComment" <AppSidebarTab v-if="acl.allowComment"
:id="'comments'" :id="'comments'"
:order="5" :order="5"
:name="t('polls', 'Comments')" :name="t('polls', 'Comments')">
icon="icon-mask-md-sidebar-comments"> <template #icon>
<SidebarCommentsIcon />
</template>
<SideBarTabComments /> <SideBarTabComments />
</AppSidebarTab> </AppSidebarTab>
@ -79,6 +87,10 @@
import { AppSidebar, AppSidebarTab } from '@nextcloud/vue' import { AppSidebar, AppSidebarTab } from '@nextcloud/vue'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { emit } from '@nextcloud/event-bus' import { emit } from '@nextcloud/event-bus'
import SidebarConfigurationIcon from 'vue-material-design-icons/Wrench.vue'
import SidebarOptionsIcon from 'vue-material-design-icons/FormatListChecks.vue'
import SidebarShareIcon from 'vue-material-design-icons/ShareVariant.vue'
import SidebarCommentsIcon from 'vue-material-design-icons/CommentProcessing.vue'
export default { export default {
name: 'SideBar', name: 'SideBar',
@ -92,6 +104,10 @@ export default {
SideBarTabActivity: () => import('../components/SideBar/SideBarTabActivity.vue'), SideBarTabActivity: () => import('../components/SideBar/SideBarTabActivity.vue'),
AppSidebar, AppSidebar,
AppSidebarTab, AppSidebarTab,
SidebarConfigurationIcon,
SidebarOptionsIcon,
SidebarShareIcon,
SidebarCommentsIcon,
}, },
props: { props: {

Просмотреть файл

@ -44,7 +44,11 @@
<div class="area__main" :class="viewMode"> <div class="area__main" :class="viewMode">
<VoteTable v-show="options.length" :view-mode="viewMode" /> <VoteTable v-show="options.length" :view-mode="viewMode" />
<EmptyContent v-if="!options.length" :icon="pollTypeIcon"> <EmptyContent v-if="!options.length">
<template #icon>
<TextPollIcon v-if="poll.type === 'textPoll'" />
<DatePollIcon v-else />
</template>
{{ t('polls', 'No vote options available') }} {{ t('polls', 'No vote options available') }}
<template #desc> <template #desc>
<button v-if="acl.allowEdit" @click="openOptions"> <button v-if="acl.allowEdit" @click="openOptions">
@ -84,6 +88,8 @@ import MarkUpDescription from '../components/Poll/MarkUpDescription.vue'
import PollInfoLine from '../components/Poll/PollInfoLine.vue' import PollInfoLine from '../components/Poll/PollInfoLine.vue'
import PollHeaderButtons from '../components/Poll/PollHeaderButtons.vue' import PollHeaderButtons from '../components/Poll/PollHeaderButtons.vue'
import HeaderBar from '../components/Base/HeaderBar.vue' import HeaderBar from '../components/Base/HeaderBar.vue'
import DatePollIcon from 'vue-material-design-icons/CalendarBlank.vue'
import TextPollIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
export default { export default {
name: 'Vote', name: 'Vote',
@ -94,6 +100,8 @@ export default {
MarkUpDescription, MarkUpDescription,
PollHeaderButtons, PollHeaderButtons,
PollInfoLine, PollInfoLine,
DatePollIcon,
TextPollIcon,
LoadingOverlay: () => import('../components/Base/LoadingOverlay.vue'), LoadingOverlay: () => import('../components/Base/LoadingOverlay.vue'),
OptionProposals: () => import('../components/Options/OptionProposals.vue'), OptionProposals: () => import('../components/Options/OptionProposals.vue'),
PublicRegisterModal: () => import('../components/Poll/PublicRegisterModal.vue'), PublicRegisterModal: () => import('../components/Poll/PublicRegisterModal.vue'),
@ -117,7 +125,6 @@ export default {
...mapGetters({ ...mapGetters({
closed: 'poll/isClosed', closed: 'poll/isClosed',
options: 'options/rankedOptions', options: 'options/rankedOptions',
pollTypeIcon: 'poll/typeIcon',
viewMode: 'poll/viewMode', viewMode: 'poll/viewMode',
proposalsAllowed: 'poll/proposalsAllowed', proposalsAllowed: 'poll/proposalsAllowed',
proposalsOpen: 'poll/proposalsOpen', proposalsOpen: 'poll/proposalsOpen',