@leavepulse/ui 0.88.0 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -312,7 +312,7 @@ from the comment that opens the component.
312
312
  - `LpPopover`: A floating panel anchored to a trigger, for content that is more than a tip.
313
313
  - `LpRelativeTime`: A date said the way people say it ("3 min ago", "in 2 h"), kept true as time passes, with the exact date one hover away.
314
314
  - `LpScrollArea`: Drawn overlay scrollbar (reka ScrollArea).
315
- - `LpSection`: A section heading: a title, an optional line under it, and actions on the right.
315
+ - `LpSection`: A section heading with no default slot: a title, an optional line under it and actions on the right; the section's content goes after it, not inside.
316
316
  - `LpSkeleton`: Loading placeholder, in two shapes.
317
317
  - `LpStatus`: What state something is in, as a light and a word: a server online, a bot starting, a region degraded.
318
318
  - `LpTooltip`: Tooltip for controls whose meaning is not written on them — an icon button, a truncated value, a disabled action that owes an explanation.
@@ -11,17 +11,17 @@
11
11
  * fade before closing the gap and the whole list lurches at the end instead of
12
12
  * gliding.
13
13
  */
14
- .lp-row-enter-active[data-v-c73bcf2c],
15
- .lp-row-leave-active[data-v-c73bcf2c] {
14
+ .lp-row-enter-active[data-v-f0750892],
15
+ .lp-row-leave-active[data-v-f0750892] {
16
16
  transition:
17
17
  opacity var(--duration-fast) var(--ease-emphasized),
18
18
  transform var(--duration-fast) var(--ease-emphasized);
19
19
  }
20
- .lp-row-move[data-v-c73bcf2c] {
20
+ .lp-row-move[data-v-f0750892] {
21
21
  transition: transform var(--duration-medium) var(--ease-emphasized);
22
22
  }
23
- .lp-row-enter-from[data-v-c73bcf2c],
24
- .lp-row-leave-to[data-v-c73bcf2c] {
23
+ .lp-row-enter-from[data-v-f0750892],
24
+ .lp-row-leave-to[data-v-f0750892] {
25
25
  opacity: 0;
26
26
  transform: translateX(-0.5rem);
27
27
  }
@@ -35,7 +35,7 @@
35
35
  * drops out of the table layout entirely. Nothing sits below this row to be
36
36
  * dragged around, so simply not animating its exit costs nothing.
37
37
  */
38
- .lp-row-empty.lp-row-leave-active[data-v-c73bcf2c] {
38
+ .lp-row-empty.lp-row-leave-active[data-v-f0750892] {
39
39
  display: none;
40
40
  }
41
41
 
@@ -54,7 +54,7 @@
54
54
  * once anything is selected. An earlier version collapsed the column to nothing
55
55
  * and floated the hover box over the first cell, where it sat on the text.
56
56
  */
57
- .lp-tick[data-v-c73bcf2c] {
57
+ .lp-tick[data-v-f0750892] {
58
58
  display: flex;
59
59
  align-items: center;
60
60
  max-width: 0;
@@ -66,17 +66,17 @@
66
66
  padding var(--duration-medium) var(--ease-emphasized),
67
67
  opacity var(--duration-fast) ease;
68
68
  }
69
- .lp-tick-open[data-v-c73bcf2c] {
69
+ .lp-tick-open[data-v-f0750892] {
70
70
  max-width: 3.25rem;
71
71
  padding-inline: 1rem;
72
72
  opacity: 1;
73
73
  }
74
- .lp-tick-hidden[data-v-c73bcf2c],
75
- .lp-tick-cue[data-v-c73bcf2c] {
74
+ .lp-tick-hidden[data-v-f0750892],
75
+ .lp-tick-cue[data-v-f0750892] {
76
76
  opacity: 0;
77
77
  }
78
- tr:hover .lp-tick-cue[data-v-c73bcf2c],
79
- .lp-tick-cue[data-v-c73bcf2c]:focus-within {
78
+ tr:hover .lp-tick-cue[data-v-f0750892],
79
+ .lp-tick-cue[data-v-f0750892]:focus-within {
80
80
  opacity: 1;
81
81
  }
82
82
 
@@ -84,15 +84,15 @@ tr:hover .lp-tick-cue[data-v-c73bcf2c],
84
84
  turned down the rows change without animating rather than not changing. */
85
85
  /* Only where there is a hover to reveal it; a finger long-presses instead. */
86
86
  @media (hover: none) {
87
- tr:hover .lp-tick-cue[data-v-c73bcf2c] {
87
+ tr:hover .lp-tick-cue[data-v-f0750892] {
88
88
  opacity: 0;
89
89
  }
90
90
 
91
91
  /* Nor is there anything for the column's width to hold until then: on a
92
92
  touch screen it stays closed until a long press starts selecting, and
93
93
  eases open like the rest of the column. */
94
- .lp-tick-hidden[data-v-c73bcf2c],
95
- .lp-tick-cue[data-v-c73bcf2c] {
94
+ .lp-tick-hidden[data-v-f0750892],
95
+ .lp-tick-cue[data-v-f0750892] {
96
96
  max-width: 0;
97
97
  padding-inline: 0;
98
98
  }
@@ -102,7 +102,7 @@ tr:hover .lp-tick-cue[data-v-c73bcf2c] {
102
102
  * A list line's tick opens from nothing, as the table's column does, so lines
103
103
  * do not carry an empty gap until selection starts.
104
104
  */
105
- .lp-tick-line[data-v-c73bcf2c] {
105
+ .lp-tick-line[data-v-f0750892] {
106
106
  max-width: 2rem;
107
107
  opacity: 1;
108
108
  }
@@ -112,28 +112,28 @@ tr:hover .lp-tick-cue[data-v-c73bcf2c] {
112
112
  * open; a cue shows it only while
113
113
  * the card is pointed at or holds focus, the same rule as a row's.
114
114
  */
115
- .lp-tick-card[data-v-c73bcf2c] {
115
+ .lp-tick-card[data-v-f0750892] {
116
116
  max-width: none;
117
117
  padding-inline: 0;
118
118
  opacity: 1;
119
119
  }
120
- .lp-tick[data-cue][data-v-c73bcf2c] {
120
+ .lp-tick[data-cue][data-v-f0750892] {
121
121
  opacity: 0;
122
122
  }
123
- .lp-item:hover .lp-tick[data-cue][data-v-c73bcf2c],
124
- .lp-tick[data-cue][data-v-c73bcf2c]:focus-within {
123
+ .lp-item:hover .lp-tick[data-cue][data-v-f0750892],
124
+ .lp-tick[data-cue][data-v-f0750892]:focus-within {
125
125
  opacity: 1;
126
126
  }
127
127
  @media (hover: none) {
128
- .lp-item:hover .lp-tick[data-cue][data-v-c73bcf2c] {
128
+ .lp-item:hover .lp-tick[data-cue][data-v-f0750892] {
129
129
  opacity: 0;
130
130
  }
131
131
  }
132
132
  @media (prefers-reduced-motion: reduce) {
133
- .lp-row-enter-active[data-v-c73bcf2c],
134
- .lp-row-leave-active[data-v-c73bcf2c],
135
- .lp-row-move[data-v-c73bcf2c],
136
- .lp-tick[data-v-c73bcf2c] {
133
+ .lp-row-enter-active[data-v-f0750892],
134
+ .lp-row-leave-active[data-v-f0750892],
135
+ .lp-row-move[data-v-f0750892],
136
+ .lp-tick[data-v-f0750892] {
137
137
  transition: none;
138
138
  }
139
139
  }
@@ -472,6 +472,13 @@ declare const __VLS_export: <T extends Record<string, unknown>>(__VLS_props: Non
472
472
  toggle: () => void;
473
473
  openMenu: (event: Event) => void;
474
474
  }) => any;
475
+ } & {
476
+ line?: (props: {
477
+ row: T;
478
+ selected: boolean;
479
+ toggle: () => void;
480
+ openMenu: (event: Event) => void;
481
+ }) => any;
475
482
  };
476
483
  emit: {
477
484
  (e: "update:selected", value: (string | number)[]): void;
@@ -34,7 +34,7 @@ import { toCsv, downloadFile, fileStem } from "./exportData.js";
34
34
  import { toHiddenSets, sameHidden, summarizeShown, parseTableState, mergeRestored, serializeTableState, fromHiddenSets } from "./tableFilter.js";
35
35
  import { resolveRowMenu } from "./tableRowMenu.js";
36
36
  import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
37
- import '../assets/LpTable-BqZNpWgC.css';const _hoisted_1 = {
37
+ import '../assets/LpTable-DAVNb-x2.css';const _hoisted_1 = {
38
38
  key: 0,
39
39
  class: "flex min-h-8 flex-wrap items-center gap-x-3 gap-y-2 pb-3 text-xs"
40
40
  };
@@ -1825,36 +1825,43 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1825
1825
  ])) : createCommentVNode("", true)
1826
1826
  ])
1827
1827
  ], true) : (openBlock(), createElementBlock("div", _hoisted_43, [
1828
- titleColumn.value ? (openBlock(), createElementBlock("div", _hoisted_44, [
1829
- renderSlot(_ctx.$slots, `cell-${titleColumn.value.key}`, {
1830
- row: entry.row,
1831
- value: entry.row[titleColumn.value.key],
1832
- openMenu: openRowMenu
1833
- }, () => [
1834
- createTextVNode(toDisplayString(entry.row[titleColumn.value.key]), 1)
1835
- ], true)
1836
- ])) : createCommentVNode("", true),
1837
- fieldColumns.value.length ? (openBlock(), createElementBlock("div", _hoisted_45, [
1838
- (openBlock(true), createElementBlock(Fragment, null, renderList(fieldColumns.value, (col, ci) => {
1839
- return openBlock(), createElementBlock(Fragment, {
1840
- key: col.key
1841
- }, [
1842
- ci > 0 ? (openBlock(), createElementBlock("span", _hoisted_46, "·")) : createCommentVNode("", true),
1843
- createElementVNode("span", {
1844
- class: "min-w-0 truncate",
1845
- title: col.label
1828
+ renderSlot(_ctx.$slots, "line", {
1829
+ row: entry.row,
1830
+ selected: isSelected(keyFor(entry.row, entry.index)),
1831
+ toggle: () => toggleRow(keyFor(entry.row, entry.index), !isSelected(keyFor(entry.row, entry.index))),
1832
+ openMenu: openRowMenu
1833
+ }, () => [
1834
+ titleColumn.value ? (openBlock(), createElementBlock("div", _hoisted_44, [
1835
+ renderSlot(_ctx.$slots, `cell-${titleColumn.value.key}`, {
1836
+ row: entry.row,
1837
+ value: entry.row[titleColumn.value.key],
1838
+ openMenu: openRowMenu
1839
+ }, () => [
1840
+ createTextVNode(toDisplayString(entry.row[titleColumn.value.key]), 1)
1841
+ ], true)
1842
+ ])) : createCommentVNode("", true),
1843
+ fieldColumns.value.length ? (openBlock(), createElementBlock("div", _hoisted_45, [
1844
+ (openBlock(true), createElementBlock(Fragment, null, renderList(fieldColumns.value, (col, ci) => {
1845
+ return openBlock(), createElementBlock(Fragment, {
1846
+ key: col.key
1846
1847
  }, [
1847
- renderSlot(_ctx.$slots, `cell-${col.key}`, {
1848
- row: entry.row,
1849
- value: entry.row[col.key],
1850
- openMenu: openRowMenu
1851
- }, () => [
1852
- createTextVNode(toDisplayString(entry.row[col.key]), 1)
1853
- ], true)
1854
- ], 8, _hoisted_47)
1855
- ], 64);
1856
- }), 128))
1857
- ])) : createCommentVNode("", true)
1848
+ ci > 0 ? (openBlock(), createElementBlock("span", _hoisted_46, "·")) : createCommentVNode("", true),
1849
+ createElementVNode("span", {
1850
+ class: "min-w-0 truncate",
1851
+ title: col.label
1852
+ }, [
1853
+ renderSlot(_ctx.$slots, `cell-${col.key}`, {
1854
+ row: entry.row,
1855
+ value: entry.row[col.key],
1856
+ openMenu: openRowMenu
1857
+ }, () => [
1858
+ createTextVNode(toDisplayString(entry.row[col.key]), 1)
1859
+ ], true)
1860
+ ], 8, _hoisted_47)
1861
+ ], 64);
1862
+ }), 128))
1863
+ ])) : createCommentVNode("", true)
1864
+ ], true)
1858
1865
  ]))
1859
1866
  ], 16, _hoisted_35))
1860
1867
  ], 64);
@@ -1880,7 +1887,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1880
1887
  };
1881
1888
  }
1882
1889
  });
1883
- const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-c73bcf2c"]]);
1890
+ const LpTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f0750892"]]);
1884
1891
  export {
1885
1892
  LpTable as default
1886
1893
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leavepulse/ui",
3
- "version": "0.88.0",
3
+ "version": "0.90.0",
4
4
  "type": "module",
5
5
  "description": "LeavePulse token-driven Vue component kit.",
6
6
  "repository": {
@@ -1,7 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  /*
3
- * A section heading: a title, an optional line under it, and actions on the
4
- * right.
3
+ * A section heading with no default slot: a title, an optional line under
4
+ * it and actions on the right; the section's content goes after it, not
5
+ * inside.
5
6
  *
6
7
  * <LpSection title="Recent invoices">
7
8
  * <template #actions><LpButton size="sm">Export</LpButton></template>
@@ -2362,7 +2362,18 @@ usePaletteCommands(() => {
2362
2362
  </dl>
2363
2363
  </div>
2364
2364
  </slot>
2365
+ <!-- `#line` is to a list line what `#card` is to a card: the inside
2366
+ only. Without it the line is built from the columns: the first
2367
+ names the row, the rest follow it in one muted line, which
2368
+ reads well for words and badly for meters or several badges. -->
2365
2369
  <div v-else class="min-w-0 flex-1">
2370
+ <slot
2371
+ name="line"
2372
+ :row="entry.row"
2373
+ :selected="isSelected(keyFor(entry.row, entry.index))"
2374
+ :toggle="() => toggleRow(keyFor(entry.row, entry.index), !isSelected(keyFor(entry.row, entry.index)))"
2375
+ :open-menu="openRowMenu"
2376
+ >
2366
2377
  <div v-if="titleColumn" class="min-w-0 truncate font-medium text-ink">
2367
2378
  <slot :name="`cell-${titleColumn.key}`" :row="entry.row" :value="entry.row[titleColumn.key]" :open-menu="openRowMenu">{{ entry.row[titleColumn.key] }}</slot>
2368
2379
  </div>
@@ -2374,7 +2385,8 @@ usePaletteCommands(() => {
2374
2385
  </span>
2375
2386
  </template>
2376
2387
  </div>
2377
- </div>
2388
+ </slot>
2389
+ </div>
2378
2390
  </div>
2379
2391
  </template>
2380
2392
  </TransitionGroup>
@@ -5,6 +5,8 @@ export interface IconCollection {
5
5
  width?: number
6
6
  height?: number
7
7
  }
8
+ export function refsInText(text: string): [prefix: string, name: string][]
9
+ export function refsInDirs(dirs: string[]): Map<string, Set<string>>
8
10
  export function namesInText(text: string): string[]
9
11
  export function namesInDirs(dirs: string[]): Set<string>
10
12
  export function subset(collection: IconCollection, names: Iterable<string>): IconCollection
@@ -1,19 +1,32 @@
1
1
  // Shared by the kit's own icon generator and the Nuxt module's app scan: find
2
- // "lucide:<name>" literals in source text and cut an iconify collection down to
3
- // just those icons (aliases keep their parent).
2
+ // "<prefix>:<name>" literals in source text and cut an iconify collection down
3
+ // to just those icons (aliases keep their parent). Any prefix is collected;
4
+ // whoever reads the result decides which prefixes are icon sets (the module
5
+ // keeps those the app has an @iconify-json package for), so "node:fs" in a
6
+ // source file costs nothing.
4
7
  import { readdirSync, readFileSync, statSync } from "node:fs"
5
8
  import { join } from "node:path"
6
9
 
7
- const NAME = /lucide:([a-z0-9]+(?:-[a-z0-9]+)*)/g
10
+ const PART = "[a-z0-9]+(?:-[a-z0-9]+)*"
11
+ const REF = new RegExp(`(?<![a-z0-9-])(${PART}):(${PART})`, "g")
8
12
  const SOURCE = /\.(vue|ts|tsx|js|jsx|mjs|md|html)$/
9
13
  const SKIP = new Set(["node_modules", "dist", ".nuxt", ".output", ".git"])
10
14
 
15
+ /** Every "<prefix>:<name>" literal, as [prefix, name] pairs. */
16
+ export function refsInText(text) {
17
+ return [...text.matchAll(REF)].map((m) => [m[1], m[2]])
18
+ }
19
+
20
+ /** The lucide names in a text. */
11
21
  export function namesInText(text) {
12
- return [...text.matchAll(NAME)].map((m) => m[1])
22
+ return refsInText(text)
23
+ .filter(([prefix]) => prefix === "lucide")
24
+ .map(([, name]) => name)
13
25
  }
14
26
 
15
- export function namesInDirs(dirs) {
16
- const names = new Set()
27
+ /** Every "<prefix>:<name>" literal under the dirs, as prefix -> names. */
28
+ export function refsInDirs(dirs) {
29
+ const refs = new Map()
17
30
  const walk = (dir) => {
18
31
  let entries
19
32
  try {
@@ -25,11 +38,21 @@ export function namesInDirs(dirs) {
25
38
  if (SKIP.has(entry)) continue
26
39
  const path = join(dir, entry)
27
40
  if (statSync(path).isDirectory()) walk(path)
28
- else if (SOURCE.test(entry)) for (const n of namesInText(readFileSync(path, "utf8"))) names.add(n)
41
+ else if (SOURCE.test(entry)) {
42
+ for (const [prefix, name] of refsInText(readFileSync(path, "utf8"))) {
43
+ if (!refs.has(prefix)) refs.set(prefix, new Set())
44
+ refs.get(prefix).add(name)
45
+ }
46
+ }
29
47
  }
30
48
  }
31
49
  for (const dir of dirs) walk(dir)
32
- return names
50
+ return refs
51
+ }
52
+
53
+ /** The lucide names under the dirs. */
54
+ export function namesInDirs(dirs) {
55
+ return refsInDirs(dirs).get("lucide") ?? new Set()
33
56
  }
34
57
 
35
58
  export function subset(collection, names) {
package/src/nuxt.ts CHANGED
@@ -18,11 +18,16 @@
18
18
  * link false to skip providing NuxtLink as the kit's link component
19
19
  * exclude component names not to auto-register (e.g. ["LayoutCanvas"]
20
20
  * when the app has its own component of that name)
21
- * icons which lucide icons render in the server pass and ship in the
22
- * main bundle: "scan" (default) finds "lucide:*" literals in the
23
- * app's source, "all" registers the whole set, "kit" only the
24
- * kit's own, or a list of names. Anything else still renders,
25
- * from a lazily loaded chunk of the bundled collection.
21
+ * icons which icons render in the server pass and ship in the main
22
+ * bundle: "scan" (default) finds "lucide:*" literals in the
23
+ * app's source, "all" registers the whole lucide set, "kit"
24
+ * only the kit's own, or a list of names. Anything else in
25
+ * lucide still renders, from a lazily loaded chunk of the
26
+ * bundled collection. Other sets ("logos:google-icon") are
27
+ * found the same way, by "scan" or in the list, for every
28
+ * prefix the app has an @iconify-json/<prefix> package for:
29
+ * registered offline from that package, never fetched from
30
+ * the iconify API.
26
31
  * propCheck false to skip the dev warning for an unknown prop on a kit
27
32
  * component (default: on in `nuxt dev`, never in a build)
28
33
  */
@@ -30,7 +35,7 @@ import { readFileSync } from "node:fs"
30
35
  import { createRequire } from "node:module"
31
36
  import { addComponent, addPlugin, addPluginTemplate, addTemplate, createResolver, defineNuxtModule } from "@nuxt/kit"
32
37
  import { COMPONENT_NAMES } from "./component-names"
33
- import { namesInDirs, subset } from "./iconSubset.mjs"
38
+ import { type IconCollection, refsInDirs, subset } from "./iconSubset.mjs"
34
39
 
35
40
  export interface LeavepulseUiOptions {
36
41
  /** Register the SSR theme plugin. Disable to wire theming yourself. */
@@ -43,18 +48,52 @@ export interface LeavepulseUiOptions {
43
48
  link?: boolean
44
49
  /** Component names to leave unregistered. */
45
50
  exclude?: string[]
46
- /** Lucide icons registered up front (default "scan"). */
51
+ /** Icons registered up front (default "scan"). */
47
52
  icons?: "scan" | "all" | "kit" | string[]
48
53
  /** Warn in `nuxt dev` about an unknown prop on a kit component (default true). */
49
54
  propCheck?: boolean
50
55
  }
51
56
 
52
- function iconsPlugin(mode: LeavepulseUiOptions["icons"], srcDir: string): string {
57
+ /** The names asked for, as prefix -> names; a bare name is lucide. */
58
+ function iconRefs(mode: LeavepulseUiOptions["icons"], srcDir: string): Map<string, Set<string>> {
59
+ if (!Array.isArray(mode)) return refsInDirs([srcDir])
60
+ const refs = new Map<string, Set<string>>()
61
+ for (const ref of mode) {
62
+ const [prefix, name] = ref.includes(":") ? ref.split(":", 2) : ["lucide", ref]
63
+ if (!refs.has(prefix!)) refs.set(prefix!, new Set())
64
+ refs.get(prefix!)!.add(name!)
65
+ }
66
+ return refs
67
+ }
68
+
69
+ /** An installed iconify set, read from the app's own dependencies; null if it has none. */
70
+ function collectionOf(prefix: string, rootDir: string): IconCollection | null {
71
+ try {
72
+ const path = createRequire(`${rootDir}/package.json`).resolve(`@iconify-json/${prefix}/icons.json`)
73
+ return JSON.parse(readFileSync(path, "utf8")) as IconCollection
74
+ } catch {
75
+ return null
76
+ }
77
+ }
78
+
79
+ export function iconsPlugin(mode: LeavepulseUiOptions["icons"], srcDir: string, rootDir: string): string {
53
80
  if (mode === "kit") return ""
54
- if (mode === "all") return 'import "@leavepulse/ui/icons-all"\n'
55
- const lucide = JSON.parse(readFileSync(createRequire(import.meta.url).resolve("@iconify-json/lucide/icons.json"), "utf8"))
56
- const names = Array.isArray(mode) ? mode.map((n) => n.replace(/^lucide:/, "")) : namesInDirs([srcDir])
57
- return `import { registerIconCollection } from "@leavepulse/ui"\nregisterIconCollection(${JSON.stringify(subset(lucide, names))})\n`
81
+ const refs = iconRefs(mode, srcDir)
82
+ const sets: IconCollection[] = []
83
+ if (mode !== "all") {
84
+ const lucide = JSON.parse(readFileSync(createRequire(import.meta.url).resolve("@iconify-json/lucide/icons.json"), "utf8"))
85
+ sets.push(subset(lucide, refs.get("lucide") ?? []))
86
+ }
87
+ for (const [prefix, names] of refs) {
88
+ if (prefix === "lucide") continue
89
+ const collection = collectionOf(prefix, rootDir)
90
+ if (!collection) continue
91
+ const cut = subset(collection, names)
92
+ if (Object.keys(cut.icons).length) sets.push(cut)
93
+ }
94
+ const head = mode === "all" ? 'import "@leavepulse/ui/icons-all"\n' : ""
95
+ if (!sets.length) return head
96
+ return `${head}import { registerIconCollection } from "@leavepulse/ui"\n${sets.map((set) => `registerIconCollection(${JSON.stringify(set)})\n`).join("")}`
58
97
  }
59
98
 
60
99
  export default defineNuxtModule<LeavepulseUiOptions>({
@@ -74,7 +113,7 @@ export default defineNuxtModule<LeavepulseUiOptions>({
74
113
  })
75
114
  }
76
115
 
77
- const icons = iconsPlugin(options.icons, nuxt.options.srcDir)
116
+ const icons = iconsPlugin(options.icons, nuxt.options.srcDir, nuxt.options.rootDir)
78
117
  if (icons) {
79
118
  addPluginTemplate({
80
119
  filename: "leavepulse-ui-icons.mjs",