[{"data":1,"prerenderedAt":930},["ShallowReactive",2],{"navigation_docs_en":3,"-en-docs-plugin-system-basics":62,"-en-docs-plugin-system-basics-surround":925},[4,9,26,37,51],{"title":5,"path":6,"stem":7,"icon":8},"Introduction","\u002Fen\u002Fdocs\u002Fintroduction","en\u002Fdocs\u002F1.introduction","i-heroicons-book-open",{"title":10,"icon":11,"path":12,"stem":13,"children":14,"page":25},"Getting Started","i-heroicons-bolt","\u002Fen\u002Fdocs\u002Fgetting-started","en\u002Fdocs\u002F2.getting-started",[15,20],{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fen\u002Fdocs\u002Fgetting-started\u002Finstallation","en\u002Fdocs\u002F2.getting-started\u002Finstallation","i-heroicons-cloud-arrow-down",{"title":21,"path":22,"stem":23,"icon":24},"Project Structure","\u002Fen\u002Fdocs\u002Fgetting-started\u002Fproject-structure","en\u002Fdocs\u002F2.getting-started\u002Fproject-structure","i-heroicons-folder",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Architecture","i-heroicons-square-3-stack-3d","\u002Fen\u002Fdocs\u002Farchitecture","en\u002Fdocs\u002F3.architecture",[32],{"title":33,"path":34,"stem":35,"icon":36},"Architecture: Nuxt Layers","\u002Fen\u002Fdocs\u002Farchitecture\u002Foverview","en\u002Fdocs\u002F3.architecture\u002Foverview","i-heroicons-cpu-chip",{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":25},"Plugin System","i-heroicons-puzzle-piece","\u002Fen\u002Fdocs\u002Fplugin-system","en\u002Fdocs\u002F4.plugin-system",[43,46],{"title":38,"path":44,"stem":45,"icon":39},"\u002Fen\u002Fdocs\u002Fplugin-system\u002Fbasics","en\u002Fdocs\u002F4.plugin-system\u002Fbasics",{"title":47,"path":48,"stem":49,"icon":50},"Override System","\u002Fen\u002Fdocs\u002Fplugin-system\u002Foverride-modes","en\u002Fdocs\u002F4.plugin-system\u002Foverride-modes","i-heroicons-arrow-path",{"title":52,"icon":53,"path":54,"stem":55,"children":56,"page":25},"Guides","i-heroicons-academic-cap","\u002Fen\u002Fdocs\u002Fguides","en\u002Fdocs\u002F5.guides",[57],{"title":58,"path":59,"stem":60,"icon":61},"Plugin Creation Guide","\u002Fen\u002Fdocs\u002Fguides\u002Fcreate-plugin","en\u002Fdocs\u002F5.guides\u002Fcreate-plugin","i-heroicons-command-line",{"id":63,"title":38,"body":64,"description":918,"extension":919,"links":920,"meta":921,"navigation":922,"path":44,"seo":923,"stem":45,"__hash__":924},"docs_en\u002Fen\u002Fdocs\u002F4.plugin-system\u002Fbasics.md",{"type":65,"value":66,"toc":912},"minimark",[67,71,84,89,99,109,113,124,146,149,360,381,385,391,413,416,442,454,458,464,887,898,901,908],[68,69,38],"h1",{"id":70},"plugin-system",[72,73,74,75,79,80,83],"p",{},"A plugin is an additional Nuxt Layer placed under ",[76,77,78],"code",{},"plugins\u002F",". Plugins are used to add new features, replace selected cores, or enrich navigation without changing source files under ",[76,81,82],{},"cores\u002F",".",[85,86,88],"h2",{"id":87},"plugin-structure","Plugin Structure",[90,91,97],"pre",{"className":92,"code":94,"language":95,"meta":96},[93],"language-text","plugins\u002Fmy-plugin\u002F\n|-- components\u002F          # Plugin components\n|-- pages\u002F               # Plugin pages\n|-- server\u002Fapi\u002F          # Plugin Nitro endpoints, when needed\n|-- stores\u002F              # Plugin Pinia stores, when needed\n|-- plugin.config.ts     # Plugin configuration\n|-- sidebar.ts           # Optional: dynamic sidebar menu provider\n`-- nuxt.config.ts       # Marks the plugin as a Nuxt Layer\n","text","",[76,98,94],{"__ignoreMap":96},[72,100,101,102,105,106,83],{},"The required files for auto-discovery are ",[76,103,104],{},"nuxt.config.ts"," and ",[76,107,108],{},"plugin.config.ts",[85,110,112],{"id":111},"current-plugin-configuration","Current Plugin Configuration",[72,114,115,116,119,120,123],{},"The plugin contract follows ",[76,117,118],{},"PluginConfig"," in ",[76,121,122],{},"shared\u002Ftypes\u002Fplugin.ts",". The main fields currently used are:",[125,126,127,134,140],"ul",{},[128,129,130,133],"li",{},[76,131,132],{},"enabled",": determines whether the plugin is active.",[128,135,136,139],{},[76,137,138],{},"routes",": route definitions that also become static sidebar menu items.",[128,141,142,145],{},[76,143,144],{},"replaces",": optional list of core ids to replace.",[72,147,148],{},"Example:",[90,150,154],{"className":151,"code":152,"language":153,"meta":96,"style":96},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import type { PluginConfig } from '..\u002F..\u002Fshared\u002Ftypes\u002Fplugin'\n\nexport default {\n  enabled: true,\n  replaces: ['program'],\n  routes: [\n    {\n      key: 'custom-class',\n      path: '\u002Fdashboard\u002Fcustom-class',\n      icon: 'i-heroicons-sparkles',\n      label: 'Custom Class'\n    }\n  ]\n} satisfies PluginConfig\n","typescript",[76,155,156,192,199,211,228,252,263,269,286,303,320,335,341,347],{"__ignoreMap":96},[157,158,161,165,168,172,176,179,182,185,189],"span",{"class":159,"line":160},"line",1,[157,162,164],{"class":163},"s7zQu","import",[157,166,167],{"class":163}," type",[157,169,171],{"class":170},"sMK4o"," {",[157,173,175],{"class":174},"sTEyZ"," PluginConfig",[157,177,178],{"class":170}," }",[157,180,181],{"class":163}," from",[157,183,184],{"class":170}," '",[157,186,188],{"class":187},"sfazB","..\u002F..\u002Fshared\u002Ftypes\u002Fplugin",[157,190,191],{"class":170},"'\n",[157,193,195],{"class":159,"line":194},2,[157,196,198],{"emptyLinePlaceholder":197},true,"\n",[157,200,202,205,208],{"class":159,"line":201},3,[157,203,204],{"class":163},"export",[157,206,207],{"class":163}," default",[157,209,210],{"class":170}," {\n",[157,212,214,218,221,225],{"class":159,"line":213},4,[157,215,217],{"class":216},"swJcz","  enabled",[157,219,220],{"class":170},":",[157,222,224],{"class":223},"sfNiH"," true",[157,226,227],{"class":170},",\n",[157,229,231,234,236,239,242,245,247,250],{"class":159,"line":230},5,[157,232,233],{"class":216},"  replaces",[157,235,220],{"class":170},[157,237,238],{"class":174}," [",[157,240,241],{"class":170},"'",[157,243,244],{"class":187},"program",[157,246,241],{"class":170},[157,248,249],{"class":174},"]",[157,251,227],{"class":170},[157,253,255,258,260],{"class":159,"line":254},6,[157,256,257],{"class":216},"  routes",[157,259,220],{"class":170},[157,261,262],{"class":174}," [\n",[157,264,266],{"class":159,"line":265},7,[157,267,268],{"class":170},"    {\n",[157,270,272,275,277,279,282,284],{"class":159,"line":271},8,[157,273,274],{"class":216},"      key",[157,276,220],{"class":170},[157,278,184],{"class":170},[157,280,281],{"class":187},"custom-class",[157,283,241],{"class":170},[157,285,227],{"class":170},[157,287,289,292,294,296,299,301],{"class":159,"line":288},9,[157,290,291],{"class":216},"      path",[157,293,220],{"class":170},[157,295,184],{"class":170},[157,297,298],{"class":187},"\u002Fdashboard\u002Fcustom-class",[157,300,241],{"class":170},[157,302,227],{"class":170},[157,304,306,309,311,313,316,318],{"class":159,"line":305},10,[157,307,308],{"class":216},"      icon",[157,310,220],{"class":170},[157,312,184],{"class":170},[157,314,315],{"class":187},"i-heroicons-sparkles",[157,317,241],{"class":170},[157,319,227],{"class":170},[157,321,323,326,328,330,333],{"class":159,"line":322},11,[157,324,325],{"class":216},"      label",[157,327,220],{"class":170},[157,329,184],{"class":170},[157,331,332],{"class":187},"Custom Class",[157,334,191],{"class":170},[157,336,338],{"class":159,"line":337},12,[157,339,340],{"class":170},"    }\n",[157,342,344],{"class":159,"line":343},13,[157,345,346],{"class":174},"  ]\n",[157,348,350,353,356],{"class":159,"line":349},14,[157,351,352],{"class":170},"}",[157,354,355],{"class":163}," satisfies",[157,357,359],{"class":358},"sBMFI"," PluginConfig\n",[72,361,362,363,366,367,366,370,366,373,376,377,380],{},"The current project does not use ",[76,364,365],{},"name",", ",[76,368,369],{},"displayName",[76,371,372],{},"version",[76,374,375],{},"overrideMode",", or ",[76,378,379],{},"targetCore"," as the primary plugin contract.",[85,382,384],{"id":383},"routes-and-sidebar","Routes and Sidebar",[72,386,387,388,390],{},"Each item in ",[76,389,138],{}," must have:",[125,392,393,399,407],{},[128,394,395,398],{},[76,396,397],{},"path",": the dashboard URL.",[128,400,401,404,405,83],{},[76,402,403],{},"icon",": a Nuxt UI\u002FIconify icon name, for example ",[76,406,315],{},[128,408,409,412],{},[76,410,411],{},"label",": the menu label.",[72,414,415],{},"Supported optional fields:",[125,417,418,424,430,436],{},[128,419,420,423],{},[76,421,422],{},"key",": a stable id for menu merging.",[128,425,426,429],{},[76,427,428],{},"children",": child menu items.",[128,431,432,435],{},[76,433,434],{},"permission",": a single permission or an array of permissions.",[128,437,438,441],{},[76,439,440],{},"meta",": custom metadata.",[72,443,444,446,447,450,451,83],{},[76,445,138],{}," is used by ",[76,448,449],{},"useSidebarMenu()"," to create static menu items. If a plugin needs dynamic menu items, add ",[76,452,453],{},"sidebar.ts",[85,455,457],{"id":456},"dynamic-sidebar","Dynamic Sidebar",[72,459,460,461,463],{},"A plugin can provide ",[76,462,453],{}," that exports a sidebar provider:",[90,465,467],{"className":151,"code":466,"language":153,"meta":96,"style":96},"import { defineSidebarProvider } from '..\u002F..\u002Fshared\u002Ftypes\u002Fmenu'\n\nexport default defineSidebarProvider(async ({ route }) => {\n  if (!route.path.startsWith('\u002Fdashboard\u002Fcustom-class')) {\n    return []\n  }\n\n  const classes = await $fetch('\u002Fapi\u002Fcustom-class\u002Fsidebar')\n\n  return [\n    {\n      key: 'custom-class',\n      path: '\u002Fdashboard\u002Fcustom-class',\n      icon: 'i-heroicons-sparkles',\n      label: 'Custom Class',\n      source: 'plugin',\n      pluginId: 'custom-class',\n      children: classes.map((item) => ({\n        key: `custom-class.${item.id}`,\n        path: `\u002Fdashboard\u002Fcustom-class\u002F${item.id}`,\n        icon: 'i-heroicons-document-text',\n        label: item.label,\n        source: 'plugin',\n        pluginId: 'custom-class'\n      }))\n    }\n  ]\n})\n",[76,468,469,489,493,524,561,569,574,578,607,611,618,622,636,650,664,679,696,712,743,772,797,814,831,847,861,870,875,880],{"__ignoreMap":96},[157,470,471,473,475,478,480,482,484,487],{"class":159,"line":160},[157,472,164],{"class":163},[157,474,171],{"class":170},[157,476,477],{"class":174}," defineSidebarProvider",[157,479,178],{"class":170},[157,481,181],{"class":163},[157,483,184],{"class":170},[157,485,486],{"class":187},"..\u002F..\u002Fshared\u002Ftypes\u002Fmenu",[157,488,191],{"class":170},[157,490,491],{"class":159,"line":194},[157,492,198],{"emptyLinePlaceholder":197},[157,494,495,497,499,502,505,509,512,516,519,522],{"class":159,"line":201},[157,496,204],{"class":163},[157,498,207],{"class":163},[157,500,477],{"class":501},"s2Zo4",[157,503,504],{"class":174},"(",[157,506,508],{"class":507},"spNyl","async",[157,510,511],{"class":170}," ({",[157,513,515],{"class":514},"sHdIc"," route",[157,517,518],{"class":170}," })",[157,520,521],{"class":507}," =>",[157,523,210],{"class":170},[157,525,526,529,532,535,538,540,542,544,547,549,551,553,555,558],{"class":159,"line":213},[157,527,528],{"class":163},"  if",[157,530,531],{"class":216}," (",[157,533,534],{"class":170},"!",[157,536,537],{"class":174},"route",[157,539,83],{"class":170},[157,541,397],{"class":174},[157,543,83],{"class":170},[157,545,546],{"class":501},"startsWith",[157,548,504],{"class":216},[157,550,241],{"class":170},[157,552,298],{"class":187},[157,554,241],{"class":170},[157,556,557],{"class":216},")) ",[157,559,560],{"class":170},"{\n",[157,562,563,566],{"class":159,"line":230},[157,564,565],{"class":163},"    return",[157,567,568],{"class":216}," []\n",[157,570,571],{"class":159,"line":254},[157,572,573],{"class":170},"  }\n",[157,575,576],{"class":159,"line":265},[157,577,198],{"emptyLinePlaceholder":197},[157,579,580,583,586,589,592,595,597,599,602,604],{"class":159,"line":271},[157,581,582],{"class":507},"  const",[157,584,585],{"class":174}," classes",[157,587,588],{"class":170}," =",[157,590,591],{"class":163}," await",[157,593,594],{"class":501}," $fetch",[157,596,504],{"class":216},[157,598,241],{"class":170},[157,600,601],{"class":187},"\u002Fapi\u002Fcustom-class\u002Fsidebar",[157,603,241],{"class":170},[157,605,606],{"class":216},")\n",[157,608,609],{"class":159,"line":288},[157,610,198],{"emptyLinePlaceholder":197},[157,612,613,616],{"class":159,"line":305},[157,614,615],{"class":163},"  return",[157,617,262],{"class":216},[157,619,620],{"class":159,"line":322},[157,621,268],{"class":170},[157,623,624,626,628,630,632,634],{"class":159,"line":337},[157,625,274],{"class":216},[157,627,220],{"class":170},[157,629,184],{"class":170},[157,631,281],{"class":187},[157,633,241],{"class":170},[157,635,227],{"class":170},[157,637,638,640,642,644,646,648],{"class":159,"line":343},[157,639,291],{"class":216},[157,641,220],{"class":170},[157,643,184],{"class":170},[157,645,298],{"class":187},[157,647,241],{"class":170},[157,649,227],{"class":170},[157,651,652,654,656,658,660,662],{"class":159,"line":349},[157,653,308],{"class":216},[157,655,220],{"class":170},[157,657,184],{"class":170},[157,659,315],{"class":187},[157,661,241],{"class":170},[157,663,227],{"class":170},[157,665,667,669,671,673,675,677],{"class":159,"line":666},15,[157,668,325],{"class":216},[157,670,220],{"class":170},[157,672,184],{"class":170},[157,674,332],{"class":187},[157,676,241],{"class":170},[157,678,227],{"class":170},[157,680,682,685,687,689,692,694],{"class":159,"line":681},16,[157,683,684],{"class":216},"      source",[157,686,220],{"class":170},[157,688,184],{"class":170},[157,690,691],{"class":187},"plugin",[157,693,241],{"class":170},[157,695,227],{"class":170},[157,697,699,702,704,706,708,710],{"class":159,"line":698},17,[157,700,701],{"class":216},"      pluginId",[157,703,220],{"class":170},[157,705,184],{"class":170},[157,707,281],{"class":187},[157,709,241],{"class":170},[157,711,227],{"class":170},[157,713,715,718,720,722,724,727,729,731,734,737,739,741],{"class":159,"line":714},18,[157,716,717],{"class":216},"      children",[157,719,220],{"class":170},[157,721,585],{"class":174},[157,723,83],{"class":170},[157,725,726],{"class":501},"map",[157,728,504],{"class":216},[157,730,504],{"class":170},[157,732,733],{"class":514},"item",[157,735,736],{"class":170},")",[157,738,521],{"class":507},[157,740,531],{"class":216},[157,742,560],{"class":170},[157,744,746,749,751,754,757,760,762,764,767,770],{"class":159,"line":745},19,[157,747,748],{"class":216},"        key",[157,750,220],{"class":170},[157,752,753],{"class":170}," `",[157,755,756],{"class":187},"custom-class.",[157,758,759],{"class":170},"${",[157,761,733],{"class":174},[157,763,83],{"class":170},[157,765,766],{"class":174},"id",[157,768,769],{"class":170},"}`",[157,771,227],{"class":170},[157,773,775,778,780,782,785,787,789,791,793,795],{"class":159,"line":774},20,[157,776,777],{"class":216},"        path",[157,779,220],{"class":170},[157,781,753],{"class":170},[157,783,784],{"class":187},"\u002Fdashboard\u002Fcustom-class\u002F",[157,786,759],{"class":170},[157,788,733],{"class":174},[157,790,83],{"class":170},[157,792,766],{"class":174},[157,794,769],{"class":170},[157,796,227],{"class":170},[157,798,800,803,805,807,810,812],{"class":159,"line":799},21,[157,801,802],{"class":216},"        icon",[157,804,220],{"class":170},[157,806,184],{"class":170},[157,808,809],{"class":187},"i-heroicons-document-text",[157,811,241],{"class":170},[157,813,227],{"class":170},[157,815,817,820,822,825,827,829],{"class":159,"line":816},22,[157,818,819],{"class":216},"        label",[157,821,220],{"class":170},[157,823,824],{"class":174}," item",[157,826,83],{"class":170},[157,828,411],{"class":174},[157,830,227],{"class":170},[157,832,834,837,839,841,843,845],{"class":159,"line":833},23,[157,835,836],{"class":216},"        source",[157,838,220],{"class":170},[157,840,184],{"class":170},[157,842,691],{"class":187},[157,844,241],{"class":170},[157,846,227],{"class":170},[157,848,850,853,855,857,859],{"class":159,"line":849},24,[157,851,852],{"class":216},"        pluginId",[157,854,220],{"class":170},[157,856,184],{"class":170},[157,858,281],{"class":187},[157,860,191],{"class":170},[157,862,864,867],{"class":159,"line":863},25,[157,865,866],{"class":170},"      }",[157,868,869],{"class":216},"))\n",[157,871,873],{"class":159,"line":872},26,[157,874,340],{"class":170},[157,876,878],{"class":159,"line":877},27,[157,879,346],{"class":216},[157,881,883,885],{"class":159,"line":882},28,[157,884,352],{"class":170},[157,886,606],{"class":174},[72,888,889,890,892,893,895,896,83],{},"Menu items from ",[76,891,453],{}," are merged with static menu items by ",[76,894,422],{}," or ",[76,897,397],{},[899,900],"hr",{},[72,902,903,904,83],{},"Learn about replacement behavior in ",[905,906,47],"a",{"href":907},"\u002Fplugin-system\u002Foverride-modes",[909,910,911],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":96,"searchDepth":194,"depth":194,"links":913},[914,915,916,917],{"id":87,"depth":194,"text":88},{"id":111,"depth":194,"text":112},{"id":383,"depth":194,"text":384},{"id":456,"depth":194,"text":457},"A plugin is an additional Nuxt Layer placed under plugins\u002F. Plugins are used to add new features, replace selected cores, or enrich navigation without changing source files under cores\u002F.","md",null,{},{"icon":39},{"title":38,"description":918},"J2Up3DoBzAJAPPeZd9HrCYundOUTnSCdiGKujO6sBpI",[926,928],{"title":33,"path":34,"stem":35,"description":927,"icon":36,"children":-1},"Alkademi LMS Open Source is built as a modular monolith. Every feature still runs inside one Nuxt application, but each domain feature is isolated as a Nuxt Layer so it can be maintained, replaced, or extended more easily.",{"title":47,"path":48,"stem":49,"description":929,"icon":50,"children":-1},"The current implementation uses two main mechanisms: extend through plugin routes\u002Flayers, and replace core through the replaces field. There is no overrideMode field read by the current source.",1780026930483]