Skip to content

Commit fb3b63a

Browse files
committed
feat: Make the app-level a component (AppLevelBadge)
Signed-off-by: Ferdinand Thiessen <[email protected]>
1 parent 84693f8 commit fb3b63a

File tree

4 files changed

+101
-70
lines changed

4 files changed

+101
-70
lines changed

apps/settings/css/settings.scss

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -594,36 +594,6 @@ span.version {
594594
color: var(--color-text-maxcontrast);
595595
}
596596

597-
.app-level {
598-
span {
599-
color: var(--color-text-maxcontrast);
600-
background-color: transparent;
601-
border: 1px solid var(--color-text-maxcontrast);
602-
border-radius: var(--border-radius);
603-
padding: 3px 6px;
604-
}
605-
606-
a {
607-
padding: 10px;
608-
margin: -6px;
609-
white-space: nowrap;
610-
}
611-
612-
.official {
613-
background-position: left center;
614-
background-position: 5px center;
615-
padding-left: 25px;
616-
}
617-
618-
.supported {
619-
border-color: var(--color-success);
620-
background-position: left center;
621-
background-position: 5px center;
622-
padding-left: 25px;
623-
color: var(--color-success);
624-
}
625-
}
626-
627597
.app-score {
628598
position: relative;
629599
top: 4px;
@@ -679,20 +649,6 @@ span.version {
679649
}
680650
}
681651

682-
.app-level {
683-
clear: right;
684-
width: 100%;
685-
686-
.supported,
687-
.official {
688-
vertical-align: top;
689-
}
690-
691-
.app-score-image {
692-
float: right;
693-
}
694-
}
695-
696652
.app-author, .app-licence {
697653
color: var(--color-text-maxcontrast);
698654
}

apps/settings/src/components/AppList/AppItem.vue

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,14 @@
4747
<component :is="dataItemTag"
4848
class="app-name"
4949
:headers="getDataItemHeaders(`app-table-col-name`)">
50-
<router-link class="app-name--link" :to="{ name: 'apps-details', params: { category: category, id: app.id }}"
50+
<router-link class="app-name--link"
51+
:to="{
52+
name: 'apps-details',
53+
params: {
54+
category: category,
55+
id: app.id
56+
},
57+
}"
5158
:aria-label="t('settings', 'Show details for {appName} app', { appName:app.name })">
5259
{{ app.name }}
5360
</router-link>
@@ -66,17 +73,8 @@
6673
<span v-else-if="app.appstoreData.releases[0].version">{{ app.appstoreData.releases[0].version }}</span>
6774
</component>
6875

69-
<component :is="dataItemTag" :headers="getDataItemHeaders(`app-table-col-level`)" class="app-level">
70-
<span v-if="app.level === 300"
71-
:title="t('settings', 'This app is supported via your current Nextcloud subscription.')"
72-
:aria-label="t('settings', 'This app is supported via your current Nextcloud subscription.')"
73-
class="supported icon-checkmark-color">
74-
{{ t('settings', 'Supported') }}</span>
75-
<span v-if="app.level === 200"
76-
:title="t('settings', 'Featured apps are developed by and within the community. They offer central functionality and are ready for production use.')"
77-
:aria-label="t('settings', 'Featured apps are developed by and within the community. They offer central functionality and are ready for production use.')"
78-
class="official icon-checkmark">
79-
{{ t('settings', 'Featured') }}</span>
76+
<component :is="dataItemTag" :headers="getDataItemHeaders(`app-table-col-level`)">
77+
<AppLevelBadge :level="app.level" />
8078
<AppScore v-if="hasRating && !listView" :score="app.score" />
8179
</component>
8280
<component :is="dataItemTag" :headers="getDataItemHeaders(`app-table-col-actions`)" class="actions">
@@ -124,19 +122,24 @@
124122

125123
<script>
126124
import AppScore from './AppScore.vue'
125+
import AppLevelBadge from './AppLevelBadge.vue'
127126
import AppManagement from '../../mixins/AppManagement.js'
128127
import SvgFilterMixin from '../SvgFilterMixin.vue'
129128
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
130129
131130
export default {
132131
name: 'AppItem',
133132
components: {
133+
AppLevelBadge,
134134
AppScore,
135135
NcButton,
136136
},
137137
mixins: [AppManagement, SvgFilterMixin],
138138
props: {
139-
app: {},
139+
app: {
140+
type: Object,
141+
required: true,
142+
},
140143
category: {},
141144
listView: {
142145
type: Boolean,
@@ -175,7 +178,7 @@ export default {
175178
this.isSelected = (this.app.id === this.$route.params.id)
176179
if (this.app.releases && this.app.screenshot) {
177180
const image = new Image()
178-
image.onload = (e) => {
181+
image.onload = () => {
179182
this.screenshotLoaded = true
180183
}
181184
image.src = this.app.screenshot
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!--
2+
- @copyright Copyright (c) 2024 Ferdinand Thiessen <[email protected]>
3+
-
4+
- @author Ferdinand Thiessen <[email protected]>
5+
-
6+
- @license AGPL-3.0-or-later
7+
-
8+
- This program is free software: you can redistribute it and/or modify
9+
- it under the terms of the GNU Affero General Public License as
10+
- published by the Free Software Foundation, either version 3 of the
11+
- License, or (at your option) any later version.
12+
-
13+
- This program is distributed in the hope that it will be useful,
14+
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
- GNU Affero General Public License for more details.
17+
-
18+
- You should have received a copy of the GNU Affero General Public License
19+
- along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
-
21+
-->
22+
<template>
23+
<span v-if="isSupported || isFeatured"
24+
class="app-level-badge"
25+
:class="{ 'app-level-badge--supported': isSupported }"
26+
:title="badgeTitle">
27+
<NcIconSvgWrapper :path="badgeIcon" :size="20" />
28+
{{ badgeText }}
29+
</span>
30+
</template>
31+
32+
<script setup lang="ts">
33+
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
34+
35+
import { mdiCheck, mdiStarShooting } from '@mdi/js'
36+
import { translate as t } from '@nextcloud/l10n'
37+
import { computed } from 'vue'
38+
39+
const props = defineProps<{
40+
/**
41+
* The app level
42+
*/
43+
level?: number
44+
}>()
45+
46+
const isSupported = computed(() => props.level === 300)
47+
const isFeatured = computed(() => props.level === 200)
48+
const badgeIcon = computed(() => isSupported.value ? mdiStarShooting : mdiCheck)
49+
const badgeText = computed(() => isSupported.value ? t('settings', 'Supported') : t('settings', 'Featured'))
50+
const badgeTitle = computed(() => isSupported.value
51+
? t('settings', 'This app is supported via your current Nextcloud subscription.')
52+
: t('settings', 'Featured apps are developed by and within the community. They offer central functionality and are ready for production use.'))
53+
</script>
54+
55+
<style scoped lang="scss">
56+
.app-level-badge {
57+
color: var(--color-text-maxcontrast);
58+
background-color: transparent;
59+
border: 1px solid var(--color-text-maxcontrast);
60+
border-radius: var(--border-radius);
61+
62+
display: flex;
63+
flex-direction: row;
64+
gap: 6px;
65+
padding: 3px 6px;
66+
67+
&--supported {
68+
border-color: var(--color-success);
69+
color: var(--color-success);
70+
}
71+
72+
// Fix the svg wrapper TODO: Remove with @nextcloud/vue 8.8.0 release
73+
:deep(.icon-vue) {
74+
min-width: unset;
75+
min-height: unset;
76+
}
77+
}
78+
</style>

apps/settings/src/views/Apps.vue

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,9 @@
105105

106106
<template #description>
107107
<!-- Featured/Supported badges -->
108-
<div v-if="app.level === 300 || app.level === 200 || hasRating" class="app-level">
109-
<span v-if="app.level === 300"
110-
:title="t('settings', 'This app is supported via your current Nextcloud subscription.')"
111-
class="supported icon-checkmark-color">
112-
{{ t('settings', 'Supported') }}</span>
113-
<span v-if="app.level === 200"
114-
:title="t('settings', 'Featured apps are developed by and within the community. They offer central functionality and are ready for production use.')"
115-
class="official icon-checkmark">
116-
{{ t('settings', 'Featured') }}</span>
117-
<AppScore v-if="hasRating" :score="app.appstoreData.ratingOverall" />
118-
</div>
108+
<AppLevelBadge :level="app.level" />
109+
<AppScore v-if="hasRating" :score="app.appstoreData.ratingOverall" />
110+
119111
<div class="app-version">
120112
<p>{{ app.version }}</p>
121113
</div>
@@ -161,6 +153,7 @@ import IconStarShooting from 'vue-material-design-icons/StarShooting.vue'
161153
import AppList from '../components/AppList.vue'
162154
import AppDetails from '../components/AppDetails.vue'
163155
import AppManagement from '../mixins/AppManagement.js'
156+
import AppLevelBadge from '../components/AppList/AppLevelBadge.vue'
164157
import AppScore from '../components/AppList/AppScore.vue'
165158
import Markdown from '../components/Markdown.vue'
166159
@@ -175,6 +168,7 @@ export default {
175168
NcAppContent,
176169
AppDetails,
177170
AppList,
171+
AppLevelBadge,
178172
IconStarShooting,
179173
NcAppNavigation,
180174
NcAppNavigationItem,
@@ -290,7 +284,7 @@ export default {
290284
this.screenshotLoaded = false
291285
if (this.app?.releases && this.app?.screenshot) {
292286
const image = new Image()
293-
image.onload = (e) => {
287+
image.onload = () => {
294288
this.screenshotLoaded = true
295289
}
296290
image.src = this.app.screenshot

0 commit comments

Comments
 (0)