Skip to content

Commit 5c5a08e

Browse files
committed
feat: add app store link for non-admins
-e Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
1 parent a8366b4 commit 5c5a08e

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

core/src/components/AppItem.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
'app-item--outlined': outlined,
1212
}"
1313
:href="app.href"
14+
:target="newTab ? '_blank' : undefined"
15+
:rel="newTab ? 'noopener noreferrer' : undefined"
1416
:aria-current="app.active ? 'page' : undefined"
1517
:tabindex="tabindex"
1618
:title="app.name"
@@ -41,6 +43,8 @@ import { computed } from 'vue'
4143
4244
const props = withDefaults(defineProps<{
4345
app: INavigationEntry
46+
/** When true, the link opens in a new tab with rel="noopener noreferrer". Used for external destinations (e.g. the app store). */
47+
newTab?: boolean
4448
/** When true, render the circle as an outline only (used for "More apps" / utility entries). */
4549
outlined?: boolean
4650
/**
@@ -50,6 +54,7 @@ const props = withDefaults(defineProps<{
5054
*/
5155
tabindex?: number
5256
}>(), {
57+
newTab: false,
5358
outlined: false,
5459
tabindex: -1,
5560
})

core/src/components/AppMenu.vue

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
:key="item.id"
4040
ref="items"
4141
:app="item"
42-
:outlined="item.id === 'more-apps'"
42+
:outlined="item.id === 'more-apps' || item.id === 'app-store'"
43+
:newTab="item.id === 'more-apps' || item.id === 'app-store'"
4344
:tabindex="i === focusedIndex ? 0 : -1" />
4445
</div>
4546
</div>
@@ -109,7 +110,9 @@ export default defineComponent({
109110
// The current-app button lives outside the slot, so we track the
110111
// source and restore focus manually via setReturnFocus.
111112
openedFrom: null as 'waffle' | 'currentApp' | null,
112-
// Synthetic admin-only tile linking to the app store; not a real nav entry.
113+
// Synthetic tile appended to the grid: admins jump to the local
114+
// app management page; everyone else lands on apps.nextcloud.com
115+
// (external, opens in a new tab via the per-tile newTab flag).
113116
moreAppsEntry: {
114117
id: 'more-apps',
115118
active: false,
@@ -121,6 +124,17 @@ export default defineComponent({
121124
unread: 0,
122125
} as INavigationEntry,
123126
127+
appStoreEntry: {
128+
id: 'app-store',
129+
active: false,
130+
order: Number.MAX_SAFE_INTEGER,
131+
href: 'https://apps.nextcloud.com/',
132+
icon: generateFilePath('settings', 'img', 'apps.svg'),
133+
type: 'link',
134+
name: t('core', 'App store'),
135+
unread: 0,
136+
} as INavigationEntry,
137+
124138
// `placement: bottom-start` swaps the anchor edge under RTL but the
125139
// skidding sign isn't auto-mirrored, so we flip it here. Snapshot
126140
// at init: Nextcloud's language doesn't change at runtime.
@@ -133,9 +147,12 @@ export default defineComponent({
133147
return this.appList.find((app) => app.active)
134148
},
135149
136-
// Stable-ordered list that focusedIndex indexes into; adds "More apps" for admins.
150+
// Stable-ordered list that focusedIndex indexes into. The trailing
151+
// utility tile is "More apps" (local app management) for admins and
152+
// "App store" (apps.nextcloud.com) for everyone else.
137153
gridItems(): INavigationEntry[] {
138-
return this.isAdmin ? [...this.appList, this.moreAppsEntry] : [...this.appList]
154+
const tail = this.isAdmin ? this.moreAppsEntry : this.appStoreEntry
155+
return [...this.appList, tail]
139156
},
140157
},
141158

0 commit comments

Comments
 (0)