11<template >
22 <div
3- v-if =" itemList .length > 0"
3+ v-if =" items .length > 0"
44 class =" app-breadcrumb"
55 >
6- <Breadcrumb :model =" itemList " >
6+ <Breadcrumb
7+ :model =" items "
8+ :home =" home "
9+ >
710 <template #item =" { item , props } " >
11+ <BaseIcon
12+ v-if =" item .icon "
13+ :icon =" item .icon "
14+ size="small"
15+ />
816 <BaseAppLink
9- v-if =" (item .route || item .url ) && item !== itemList [ itemList .length - 1 ] "
17+ v-if =" (item .route || item .url ) && item !== items [ items .length - 1 ] "
1018 :to =" item .route "
1119 :url =" item .url "
1220 v-bind =" props .action "
1725 <span
1826 v-else
1927 v-text =" stripHtml(item.label)"
20- ></span >
28+ v-bind =" props.action"
29+ />
2130 </template >
2231
2332 <template #separator > /</template >
@@ -38,6 +47,7 @@ import Breadcrumb from "primevue/breadcrumb"
3847import { useCidReqStore } from " ../store/cidReq"
3948import { storeToRefs } from " pinia"
4049import { useStore } from " vuex"
50+ import BaseIcon from " ./basecomponents/BaseIcon.vue"
4151
4252const legacyItems = ref ([])
4353
@@ -62,7 +72,26 @@ const specialRouteNames = [
6272 " MessageCreate" ,
6373]
6474
65- const itemList = ref ([])
75+ const calculatedList = ref ([])
76+
77+ const home = computed (() => {
78+ if (calculatedList .value .length ) {
79+ return {
80+ ... calculatedList .value [0 ],
81+ icon: " compass" ,
82+ }
83+ }
84+
85+ return undefined
86+ })
87+
88+ const items = computed (() => {
89+ if (! calculatedList .value .length ) {
90+ return []
91+ }
92+
93+ return calculatedList .value .slice (1 )
94+ })
6695
6796/**
6897 * Group breadcrumb support (no API calls)
@@ -87,7 +116,7 @@ const formatToolName = (name) => {
87116}
88117
89118const addToolWithResourceBreadcrumb = (toolName , listRouteName , detailRouteName ) => {
90- itemList .value .push ({
119+ calculatedList .value .push ({
91120 label: t (formatToolName (toolName)),
92121 route: {
93122 name: listRouteName,
@@ -104,7 +133,7 @@ const addToolWithResourceBreadcrumb = (toolName, listRouteName, detailRouteName)
104133 const resourceLabel = resourceNode .value .title
105134 const idParam = cleanIdParam (route .params .id )
106135
107- itemList .value .push ({
136+ calculatedList .value .push ({
108137 label: resourceLabel,
109138 route: idParam ? { name: detailRouteName, params: { id: idParam }, query: route .query } : undefined ,
110139 })
@@ -114,7 +143,7 @@ const addToolWithResourceBreadcrumb = (toolName, listRouteName, detailRouteName)
114143 const label = currentMatched? .meta ? .breadcrumb || formatToolName (route .name )
115144
116145 if (route .name !== detailRouteName) {
117- itemList .value .push ({
146+ calculatedList .value .push ({
118147 label: t (label),
119148 route: { name: route .name , params: route .params , query: route .query },
120149 })
@@ -125,10 +154,10 @@ function addRemainingMatchedBreadcrumbs() {
125154 route .matched .slice (1 ).forEach ((r ) => {
126155 const label = r .meta ? .breadcrumb || formatToolName (r .name )
127156 const alreadyHasResource =
128- resourceNode .value ? .title && itemList .value .some ((item ) => item .label === resourceNode .value .title )
157+ resourceNode .value ? .title && calculatedList .value .some ((item ) => item .label === resourceNode .value .title )
129158
130159 if (! alreadyHasResource) {
131- itemList .value .push ({
160+ calculatedList .value .push ({
132161 label: t (label),
133162 route: {
134163 name: r .name ,
@@ -177,7 +206,7 @@ function addDocumentBreadcrumb() {
177206 current = current .parent
178207 }
179208 const first = folderTrail .shift ()
180- itemList .value .push ({
209+ calculatedList .value .push ({
181210 label: t (" Documents" ),
182211 route: {
183212 name: " DocumentsList" ,
@@ -186,7 +215,7 @@ function addDocumentBreadcrumb() {
186215 },
187216 })
188217 folderTrail .forEach ((folder ) => {
189- itemList .value .push ({
218+ calculatedList .value .push ({
190219 label: folder .label ,
191220 route: { name: " DocumentsList" , params: { node: folder .nodeId }, query: route .query },
192221 })
@@ -196,9 +225,9 @@ function addDocumentBreadcrumb() {
196225 const label = currentMatched? .meta ? .breadcrumb
197226 if (label !== " " ) {
198227 const finalLabel = label || formatToolName (currentMatched? .name )
199- const alreadyShown = itemList .value .some ((item ) => item .label === finalLabel)
228+ const alreadyShown = calculatedList .value .some ((item ) => item .label === finalLabel)
200229 if (! alreadyShown) {
201- itemList .value .push ({
230+ calculatedList .value .push ({
202231 label: t (finalLabel),
203232 route: { name: currentMatched .name , params: route .params , query: route .query },
204233 })
@@ -220,13 +249,13 @@ function addGroupBreadcrumbIfNeeded() {
220249 const label = ` ${ labelBase} ${ padded} `
221250
222251 // Avoid duplicates (e.g. if some legacy breadcrumb already includes it)
223- const alreadyExists = itemList .value .some ((it ) => stripHtml (it .label ) === stripHtml (label))
252+ const alreadyExists = calculatedList .value .some ((it ) => stripHtml (it .label ) === stripHtml (label))
224253 if (alreadyExists) return
225254
226255 // Legacy group space URL, works even if there is no Vue route for group space
227256 const url = buildGroupSpaceUrl (currentGid)
228257
229- itemList .value .push ({
258+ calculatedList .value .push ({
230259 label,
231260 url: url || undefined ,
232261 })
@@ -296,22 +325,22 @@ function resolveSettingsSectionLabel(nsRaw) {
296325// Watch route changes to dynamically rebuild the breadcrumb trail
297326watchEffect (() => {
298327 if (" /" === route .fullPath ) return
299- itemList .value = []
300- // special-case accessurl routes
328+ calculatedList .value = []
329+ // special-case accessurl routes
301330 if (/ ^ \/ resources\/ accessurl\/ [^ \/ ] + \/ delete(?:\/ | $ )/ .test (route .path )) {
302- itemList .value = []
331+ calculatedList .value = []
303332
304- itemList .value .push ({
333+ calculatedList .value .push ({
305334 label: t (" Administration" ),
306335 url: " /main/admin/index.php" ,
307336 })
308337
309- itemList .value .push ({
338+ calculatedList .value .push ({
310339 label: t (" Multiple access URL / Branding" ),
311340 url: " /main/admin/access_urls.php" ,
312341 })
313342
314- itemList .value .push ({ label: t (" Delete access" ) })
343+ calculatedList .value .push ({ label: t (" Delete access" ) })
315344
316345 return
317346 }
@@ -320,18 +349,18 @@ watchEffect(() => {
320349
321350 // Static route categories (must use "route" or "url" for our slot)
322351 if (route .name ? .includes (" Page" )) {
323- itemList .value .push ({ label: t (" Pages" ), route: { path: " /resources/pages" } })
352+ calculatedList .value .push ({ label: t (" Pages" ), route: { path: " /resources/pages" } })
324353 }
325354 if (route .name ? .includes (" Message" )) {
326- itemList .value .push ({ label: t (" Messages" ), route: { path: " /resources/messages" } })
355+ calculatedList .value .push ({ label: t (" Messages" ), route: { path: " /resources/messages" } })
327356 }
328357
329358 // Do not build breadcrumb for top-level routes
330359 if (specialRouteNames .includes (route .name )) return
331360
332361 // Add course or session link
333362 if (course .value ) {
334- itemList .value .push ({
363+ calculatedList .value .push ({
335364 label: t (session .value ? " My sessions" : " My courses" ),
336365 route: { name: session .value ? " MySessions" : " MyCourses" },
337366 })
@@ -345,15 +374,15 @@ watchEffect(() => {
345374 let newUrl = (item .url || " " ).toString ()
346375 if (newUrl .indexOf (" main/" ) > 0 ) newUrl = " /" + newUrl .substring (mainPath)
347376 if (newUrl === " /" ) newUrl = " #"
348- itemList .value .push ({ label: item .name , url: newUrl || undefined })
377+ calculatedList .value .push ({ label: item .name , url: newUrl || undefined })
349378 })
350379 legacyItems .value = []
351380 return
352381 }
353382
354383 // Standard: add course title crumb
355384 if (course .value && route .name !== " CourseHome" ) {
356- itemList .value .push ({
385+ calculatedList .value .push ({
357386 label: course .value .title ,
358387 route: { name: " CourseHome" , params: { id: course .value .id }, query: route .query },
359388 })
@@ -399,17 +428,17 @@ watchEffect(() => {
399428 const gidVal = Number (route .query ? .gid || 0 )
400429 toolLabel = gidVal > 0 ? " Group agenda" : cid > 0 ? " Agenda" : " Personal agenda"
401430 }
402- itemList .value .push ({
431+ calculatedList .value .push ({
403432 label: t (toolLabel),
404433 route: { name: toolBase .name , params: route .params , query: route .query },
405434 })
406435
407436 const label = currentMatched .meta ? .breadcrumb
408437 if (label !== " " ) {
409438 const finalLabel = label || formatToolName (currentMatched .name )
410- const alreadyShown = itemList .value .some ((item ) => item .label === finalLabel)
439+ const alreadyShown = calculatedList .value .some ((item ) => item .label === finalLabel)
411440 if (! alreadyShown) {
412- itemList .value .push ({
441+ calculatedList .value .push ({
413442 label: t (finalLabel),
414443 route: { name: currentMatched .name , params: route .params , query: route .query },
415444 })
@@ -441,7 +470,7 @@ function buildManualBreadcrumbIfNeeded() {
441470 let newUrl = (item .url || " " ).toString ()
442471 if (newUrl .indexOf (" main/" ) > 0 ) newUrl = " /" + newUrl .substring (mainPath)
443472 if (newUrl === " /" ) newUrl = " #"
444- itemList .value .push ({ label: item .name , url: newUrl || undefined })
473+ calculatedList .value .push ({ label: item .name , url: newUrl || undefined })
445474 })
446475 legacyItems .value = []
447476 return true
@@ -464,16 +493,16 @@ function buildManualBreadcrumbIfNeeded() {
464493 if (isAdminSettings) {
465494 const ns = pathSegments[2 ] || route .params ? .namespace || route .query ? .namespace || " "
466495 const adminLabel = t (" Admin" )
467- itemList .value .push ({
496+ calculatedList .value .push ({
468497 label: adminLabel,
469498 route: { name: overrides .admin , params: route .params , query: route .query },
470499 })
471- itemList .value .push ({
500+ calculatedList .value .push ({
472501 label: t (" Settings" ),
473502 route: { path: " /admin/settings" },
474503 })
475504 const section = resolveSettingsSectionLabel (ns)
476- itemList .value .push ({ label: section })
505+ calculatedList .value .push ({ label: section })
477506 return true
478507 }
479508
@@ -488,15 +517,15 @@ function buildManualBreadcrumbIfNeeded() {
488517 const label = t (segment .charAt (0 ).toUpperCase () + segment .slice (1 ))
489518 const override = overrides[segment]
490519 if (override === null ) {
491- itemList .value .push ({ label })
520+ calculatedList .value .push ({ label })
492521 } else if (override) {
493- itemList .value .push ({
522+ calculatedList .value .push ({
494523 label,
495524 route: { name: override, params: route .params , query: route .query },
496525 })
497526 } else {
498527 const partialPath = " /" + pathSegments .slice (0 , index + 1 ).join (" /" )
499- itemList .value .push ({
528+ calculatedList .value .push ({
500529 label,
501530 route: { path: partialPath },
502531 })
@@ -567,7 +596,7 @@ function buildSkillBreadcrumbIfNeeded() {
567596
568597 const rootUrl = origin || (isSocial ? " /social" : " /admin" )
569598
570- itemList .value .push ({
599+ calculatedList .value .push ({
571600 label: rootLabel,
572601 url: rootUrl,
573602 })
@@ -576,7 +605,7 @@ function buildSkillBreadcrumbIfNeeded() {
576605 const lastLabel =
577606 route .name === " SkillWheel" ? translateOrFallback (" Skills wheel" , " Skills wheel" ) : formatToolName (route .name )
578607
579- itemList .value .push ({ label: lastLabel })
608+ calculatedList .value .push ({ label: lastLabel })
580609
581610 return true
582611}
0 commit comments