@maizzle/framework 6.0.0-rc.12 → 6.0.0-rc.13

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.
Files changed (49) hide show
  1. package/dist/build.mjs +4 -1
  2. package/dist/build.mjs.map +1 -1
  3. package/dist/serve.d.mts.map +1 -1
  4. package/dist/serve.mjs +22 -10
  5. package/dist/serve.mjs.map +1 -1
  6. package/dist/server/compatibility.d.mts +54 -2
  7. package/dist/server/compatibility.d.mts.map +1 -1
  8. package/dist/server/compatibility.mjs +890 -76
  9. package/dist/server/compatibility.mjs.map +1 -1
  10. package/dist/server/linter.d.mts +15 -2
  11. package/dist/server/linter.d.mts.map +1 -1
  12. package/dist/server/linter.mjs +194 -43
  13. package/dist/server/linter.mjs.map +1 -1
  14. package/dist/server/sfc-utils.d.mts +18 -0
  15. package/dist/server/sfc-utils.d.mts.map +1 -0
  16. package/dist/server/sfc-utils.mjs +184 -0
  17. package/dist/server/sfc-utils.mjs.map +1 -0
  18. package/dist/server/ui/App.vue +4 -41
  19. package/dist/server/ui/components/SidebarClose.vue +12 -0
  20. package/dist/server/ui/components/ui/command/Command.vue +1 -0
  21. package/dist/server/ui/components/ui/input/Input.vue +1 -1
  22. package/dist/server/ui/components/ui/sidebar/SidebarTrigger.vue +1 -1
  23. package/dist/server/ui/components/ui/tags-input/TagsInputInput.vue +1 -1
  24. package/dist/server/ui/pages/Preview.vue +191 -151
  25. package/dist/transformers/addAttributes.mjs +10 -6
  26. package/dist/transformers/addAttributes.mjs.map +1 -1
  27. package/dist/transformers/inlineCSS.mjs +2 -2
  28. package/dist/transformers/inlineCSS.mjs.map +1 -1
  29. package/dist/transformers/purgeCSS.mjs +1 -1
  30. package/dist/transformers/purgeCSS.mjs.map +1 -1
  31. package/dist/transformers/tailwindcss.mjs +2 -4
  32. package/dist/transformers/tailwindcss.mjs.map +1 -1
  33. package/dist/types/config.d.mts +42 -2
  34. package/dist/types/config.d.mts.map +1 -1
  35. package/dist/types/index.d.mts +2 -2
  36. package/package.json +1 -3
  37. package/dist/_virtual/_rolldown/runtime.mjs +0 -32
  38. package/dist/node_modules/picomatch/index.mjs +0 -13
  39. package/dist/node_modules/picomatch/index.mjs.map +0 -1
  40. package/dist/node_modules/picomatch/lib/constants.mjs +0 -174
  41. package/dist/node_modules/picomatch/lib/constants.mjs.map +0 -1
  42. package/dist/node_modules/picomatch/lib/parse.mjs +0 -1067
  43. package/dist/node_modules/picomatch/lib/parse.mjs.map +0 -1
  44. package/dist/node_modules/picomatch/lib/picomatch.mjs +0 -304
  45. package/dist/node_modules/picomatch/lib/picomatch.mjs.map +0 -1
  46. package/dist/node_modules/picomatch/lib/scan.mjs +0 -296
  47. package/dist/node_modules/picomatch/lib/scan.mjs.map +0 -1
  48. package/dist/node_modules/picomatch/lib/utils.mjs +0 -53
  49. package/dist/node_modules/picomatch/lib/utils.mjs.map +0 -1
@@ -0,0 +1,184 @@
1
+ import { existsSync } from "node:fs";
2
+ import { basename, dirname, resolve } from "node:path";
3
+ import { glob } from "tinyglobby";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ //#region src/server/sfc-utils.ts
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ function parseSfcBlocks(source) {
9
+ let template = null;
10
+ const styles = [];
11
+ const templateMatch = source.match(/<template\b[^>]*>([\s\S]*)<\/template>/);
12
+ if (templateMatch) {
13
+ const contentStart = source.indexOf(templateMatch[0]) + templateMatch[0].indexOf(templateMatch[1]);
14
+ const offset = source.slice(0, contentStart).split("\n").length - 1;
15
+ template = {
16
+ content: templateMatch[1],
17
+ offset
18
+ };
19
+ }
20
+ const styleRe = /<style\b([^>]*)>([\s\S]*?)<\/style>/g;
21
+ let m;
22
+ while ((m = styleRe.exec(source)) !== null) {
23
+ if (/\blang\s*=\s*["'](?!css)/i.test(m[1])) continue;
24
+ const contentStart = m.index + m[0].indexOf(m[2]);
25
+ const offset = source.slice(0, contentStart).split("\n").length - 1;
26
+ styles.push({
27
+ content: m[2],
28
+ offset
29
+ });
30
+ }
31
+ return {
32
+ template,
33
+ styles
34
+ };
35
+ }
36
+ /**
37
+ * Standard HTML elements — anything not in this set is treated as a component.
38
+ */
39
+ const HTML_ELEMENTS = new Set([
40
+ "a",
41
+ "abbr",
42
+ "address",
43
+ "area",
44
+ "article",
45
+ "aside",
46
+ "audio",
47
+ "b",
48
+ "base",
49
+ "bdi",
50
+ "bdo",
51
+ "blockquote",
52
+ "body",
53
+ "br",
54
+ "button",
55
+ "canvas",
56
+ "caption",
57
+ "cite",
58
+ "code",
59
+ "col",
60
+ "colgroup",
61
+ "data",
62
+ "datalist",
63
+ "dd",
64
+ "del",
65
+ "details",
66
+ "dfn",
67
+ "dialog",
68
+ "div",
69
+ "dl",
70
+ "dt",
71
+ "em",
72
+ "embed",
73
+ "fieldset",
74
+ "figcaption",
75
+ "figure",
76
+ "footer",
77
+ "form",
78
+ "h1",
79
+ "h2",
80
+ "h3",
81
+ "h4",
82
+ "h5",
83
+ "h6",
84
+ "head",
85
+ "header",
86
+ "hgroup",
87
+ "hr",
88
+ "html",
89
+ "i",
90
+ "iframe",
91
+ "img",
92
+ "input",
93
+ "ins",
94
+ "kbd",
95
+ "label",
96
+ "legend",
97
+ "li",
98
+ "link",
99
+ "main",
100
+ "map",
101
+ "mark",
102
+ "menu",
103
+ "meta",
104
+ "meter",
105
+ "nav",
106
+ "noscript",
107
+ "object",
108
+ "ol",
109
+ "optgroup",
110
+ "option",
111
+ "output",
112
+ "p",
113
+ "picture",
114
+ "pre",
115
+ "progress",
116
+ "q",
117
+ "rp",
118
+ "rt",
119
+ "ruby",
120
+ "s",
121
+ "samp",
122
+ "script",
123
+ "search",
124
+ "section",
125
+ "select",
126
+ "slot",
127
+ "small",
128
+ "source",
129
+ "span",
130
+ "strong",
131
+ "style",
132
+ "sub",
133
+ "summary",
134
+ "sup",
135
+ "table",
136
+ "tbody",
137
+ "td",
138
+ "template",
139
+ "textarea",
140
+ "tfoot",
141
+ "th",
142
+ "thead",
143
+ "time",
144
+ "title",
145
+ "tr",
146
+ "track",
147
+ "u",
148
+ "ul",
149
+ "var",
150
+ "video",
151
+ "wbr"
152
+ ]);
153
+ function findComponentTags(templateContent) {
154
+ const tags = /* @__PURE__ */ new Set();
155
+ const pascalRe = /<([A-Z][a-zA-Z0-9]*)\b/g;
156
+ let m;
157
+ while ((m = pascalRe.exec(templateContent)) !== null) tags.add(m[1]);
158
+ const kebabRe = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\b/g;
159
+ while ((m = kebabRe.exec(templateContent)) !== null) if (!HTML_ELEMENTS.has(m[1])) tags.add(m[1]);
160
+ return [...tags];
161
+ }
162
+ async function buildComponentMap(root, componentDirs) {
163
+ const map = /* @__PURE__ */ new Map();
164
+ const dirs = [
165
+ resolve(__dirname, "../components"),
166
+ resolve(root, "components"),
167
+ ...componentDirs
168
+ ].filter((d) => existsSync(d));
169
+ for (const dir of dirs) {
170
+ const files = await glob(["**/*.vue"], {
171
+ cwd: dir,
172
+ absolute: true
173
+ });
174
+ for (const file of files) {
175
+ const name = basename(file, ".vue");
176
+ map.set(name.toLowerCase(), file);
177
+ }
178
+ }
179
+ return map;
180
+ }
181
+
182
+ //#endregion
183
+ export { HTML_ELEMENTS, buildComponentMap, findComponentTags, parseSfcBlocks };
184
+ //# sourceMappingURL=sfc-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sfc-utils.mjs","names":[],"sources":["../../src/server/sfc-utils.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve, dirname, basename } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { glob } from 'tinyglobby'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface SfcBlock {\n content: string\n offset: number\n}\n\nexport function parseSfcBlocks(source: string): { template: SfcBlock | null, styles: SfcBlock[] } {\n let template: SfcBlock | null = null\n const styles: SfcBlock[] = []\n\n const templateMatch = source.match(/<template\\b[^>]*>([\\s\\S]*)<\\/template>/)\n if (templateMatch) {\n const contentStart = source.indexOf(templateMatch[0]) + templateMatch[0].indexOf(templateMatch[1])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n template = { content: templateMatch[1], offset }\n }\n\n const styleRe = /<style\\b([^>]*)>([\\s\\S]*?)<\\/style>/g\n let m\n while ((m = styleRe.exec(source)) !== null) {\n // Skip preprocessor styles (scss, less, etc.) — caniemail only parses plain CSS\n if (/\\blang\\s*=\\s*[\"'](?!css)/i.test(m[1])) continue\n\n const contentStart = m.index + m[0].indexOf(m[2])\n const offset = source.slice(0, contentStart).split('\\n').length - 1\n styles.push({ content: m[2], offset })\n }\n\n return { template, styles }\n}\n\n/**\n * Standard HTML elements — anything not in this set is treated as a component.\n */\nexport const HTML_ELEMENTS = new Set([\n 'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'base',\n 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption',\n 'cite', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del',\n 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset',\n 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',\n 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', 'img',\n 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'main', 'map',\n 'mark', 'menu', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol',\n 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q',\n 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select',\n 'slot', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary',\n 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th',\n 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr',\n])\n\nexport function findComponentTags(templateContent: string): string[] {\n const tags = new Set<string>()\n\n // PascalCase tags like <Section>, <Button>\n const pascalRe = /<([A-Z][a-zA-Z0-9]*)\\b/g\n let m\n while ((m = pascalRe.exec(templateContent)) !== null) {\n tags.add(m[1])\n }\n\n // kebab-case tags like <my-component>\n const kebabRe = /<([a-z][a-z0-9]*(?:-[a-z0-9]+)+)\\b/g\n while ((m = kebabRe.exec(templateContent)) !== null) {\n if (!HTML_ELEMENTS.has(m[1])) {\n tags.add(m[1])\n }\n }\n\n return [...tags]\n}\n\nexport async function buildComponentMap(root: string, componentDirs: string[]): Promise<Map<string, string>> {\n const map = new Map<string, string>()\n\n const dirs = [\n resolve(__dirname, '../components'),\n resolve(root, 'components'),\n ...componentDirs,\n ].filter(d => existsSync(d))\n\n for (const dir of dirs) {\n const files = await glob(['**/*.vue'], { cwd: dir, absolute: true })\n for (const file of files) {\n const name = basename(file, '.vue')\n // Store lowercased for case-insensitive matching\n map.set(name.toLowerCase(), file)\n }\n }\n\n return map\n}\n"],"mappings":";;;;;;AAKA,MAAM,YAAY,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAOzD,SAAgB,eAAe,QAAmE;CAChG,IAAI,WAA4B;CAChC,MAAM,SAAqB,EAAE;CAE7B,MAAM,gBAAgB,OAAO,MAAM,yCAAyC;AAC5E,KAAI,eAAe;EACjB,MAAM,eAAe,OAAO,QAAQ,cAAc,GAAG,GAAG,cAAc,GAAG,QAAQ,cAAc,GAAG;EAClG,MAAM,SAAS,OAAO,MAAM,GAAG,aAAa,CAAC,MAAM,KAAK,CAAC,SAAS;AAClE,aAAW;GAAE,SAAS,cAAc;GAAI;GAAQ;;CAGlD,MAAM,UAAU;CAChB,IAAI;AACJ,SAAQ,IAAI,QAAQ,KAAK,OAAO,MAAM,MAAM;AAE1C,MAAI,4BAA4B,KAAK,EAAE,GAAG,CAAE;EAE5C,MAAM,eAAe,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG;EACjD,MAAM,SAAS,OAAO,MAAM,GAAG,aAAa,CAAC,MAAM,KAAK,CAAC,SAAS;AAClE,SAAO,KAAK;GAAE,SAAS,EAAE;GAAI;GAAQ,CAAC;;AAGxC,QAAO;EAAE;EAAU;EAAQ;;;;;AAM7B,MAAa,gBAAgB,IAAI,IAAI;CACnC;CAAK;CAAQ;CAAW;CAAQ;CAAW;CAAS;CAAS;CAAK;CAClE;CAAO;CAAO;CAAc;CAAQ;CAAM;CAAU;CAAU;CAC9D;CAAQ;CAAQ;CAAO;CAAY;CAAQ;CAAY;CAAM;CAC7D;CAAW;CAAO;CAAU;CAAO;CAAM;CAAM;CAAM;CAAS;CAC9D;CAAc;CAAU;CAAU;CAAQ;CAAM;CAAM;CAAM;CAAM;CAClE;CAAM;CAAQ;CAAU;CAAU;CAAM;CAAQ;CAAK;CAAU;CAC/D;CAAS;CAAO;CAAO;CAAS;CAAU;CAAM;CAAQ;CAAQ;CAChE;CAAQ;CAAQ;CAAQ;CAAS;CAAO;CAAY;CAAU;CAC9D;CAAY;CAAU;CAAU;CAAK;CAAW;CAAO;CAAY;CACnE;CAAM;CAAM;CAAQ;CAAK;CAAQ;CAAU;CAAU;CAAW;CAChE;CAAQ;CAAS;CAAU;CAAQ;CAAU;CAAS;CAAO;CAC7D;CAAO;CAAS;CAAS;CAAM;CAAY;CAAY;CAAS;CAChE;CAAS;CAAQ;CAAS;CAAM;CAAS;CAAK;CAAM;CAAO;CAAS;CACrE,CAAC;AAEF,SAAgB,kBAAkB,iBAAmC;CACnE,MAAM,uBAAO,IAAI,KAAa;CAG9B,MAAM,WAAW;CACjB,IAAI;AACJ,SAAQ,IAAI,SAAS,KAAK,gBAAgB,MAAM,KAC9C,MAAK,IAAI,EAAE,GAAG;CAIhB,MAAM,UAAU;AAChB,SAAQ,IAAI,QAAQ,KAAK,gBAAgB,MAAM,KAC7C,KAAI,CAAC,cAAc,IAAI,EAAE,GAAG,CAC1B,MAAK,IAAI,EAAE,GAAG;AAIlB,QAAO,CAAC,GAAG,KAAK;;AAGlB,eAAsB,kBAAkB,MAAc,eAAuD;CAC3G,MAAM,sBAAM,IAAI,KAAqB;CAErC,MAAM,OAAO;EACX,QAAQ,WAAW,gBAAgB;EACnC,QAAQ,MAAM,aAAa;EAC3B,GAAG;EACJ,CAAC,QAAO,MAAK,WAAW,EAAE,CAAC;AAE5B,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,MAAM,KAAK,CAAC,WAAW,EAAE;GAAE,KAAK;GAAK,UAAU;GAAM,CAAC;AACpE,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,OAAO,SAAS,MAAM,OAAO;AAEnC,OAAI,IAAI,KAAK,aAAa,EAAE,KAAK;;;AAIrC,QAAO"}
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed, onMounted, onUnmounted, watch, watchEffect } from 'vue'
3
3
  import { RouterLink, RouterView, useRoute, useRouter } from 'vue-router'
4
- import { Monitor, CodeXml, Smartphone, ChevronDown, ArrowUp, ArrowDown, CornerDownLeft, Check, Search, Camera, FileCode, FileText, Code, BookText, MailQuestion } from 'lucide-vue-next'
5
- import { toBlob } from 'html-to-image'
4
+ import { Monitor, CodeXml, Smartphone, ChevronDown, ArrowUp, ArrowDown, CornerDownLeft, Check, Search, FileCode, FileText, Code, BookText, MailQuestion } from 'lucide-vue-next'
5
+ import SidebarClose from '@/components/SidebarClose.vue'
6
6
  import logoUrl from '@/logo.svg'
7
7
  import logoGradientUrl from '@/logo-gradient.svg'
8
8
  import { Kbd } from '@/components/ui/kbd'
@@ -136,32 +136,6 @@ watch(commandOpen, (open) => {
136
136
  if (!open) commandSearch.value = ''
137
137
  })
138
138
 
139
- const screenshotting = ref(false)
140
-
141
- async function copyScreenshot() {
142
- commandOpen.value = false
143
-
144
- const iframe = document.querySelector('iframe') as HTMLIFrameElement | null
145
- const doc = iframe?.contentDocument
146
- if (!doc?.body) return
147
-
148
- screenshotting.value = true
149
-
150
- try {
151
- const blob = await toBlob(doc.body, {
152
- width: doc.body.scrollWidth,
153
- height: doc.body.scrollHeight,
154
- })
155
-
156
- if (blob) {
157
- await navigator.clipboard.write([
158
- new ClipboardItem({ 'image/png': blob })
159
- ])
160
- }
161
- } finally {
162
- screenshotting.value = false
163
- }
164
- }
165
139
 
166
140
  async function copyHtml() {
167
141
  commandOpen.value = false
@@ -240,10 +214,6 @@ function onKeydown(e: KeyboardEvent) {
240
214
  // Copy shortcuts (Cmd on Mac, Alt on Win/Linux)
241
215
  if ((isMac ? e.metaKey : e.altKey) && !e.shiftKey && isPreviewRoute.value) {
242
216
  switch (e.key.toLowerCase()) {
243
- case 's':
244
- e.preventDefault()
245
- copyScreenshot()
246
- return
247
217
  case 'c':
248
218
  e.preventDefault()
249
219
  copyHtml()
@@ -289,13 +259,14 @@ onUnmounted(() => {
289
259
  <img :src="logoUrl" alt="Maizzle" class="h-4 dark:hidden">
290
260
  <img :src="logoGradientUrl" alt="Maizzle" class="hidden h-4 dark:block">
291
261
  </RouterLink>
292
- <button class="inline-flex items-center gap-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" @click="commandOpen = true">
262
+ <button class="hidden md:inline-flex items-center gap-1.5 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" @click="commandOpen = true">
293
263
  <Search class="size-3.5" />
294
264
  <kbd class="flex items-center gap-0.5 text-[10px] font-sans">
295
265
  <span>{{ modKey }}</span>
296
266
  <span class="text-gray-300 dark:text-gray-600">K</span>
297
267
  </kbd>
298
268
  </button>
269
+ <SidebarClose />
299
270
  </SidebarHeader>
300
271
 
301
272
  <SidebarContent>
@@ -406,14 +377,6 @@ onUnmounted(() => {
406
377
 
407
378
  <!-- Copy to clipboard commands -->
408
379
  <CommandGroup v-if="isPreviewRoute" heading="Copy to clipboard">
409
- <CommandItem
410
- value="Screenshot"
411
- @select="copyScreenshot"
412
- >
413
- <Camera class="size-3 shrink-0 opacity-50" />
414
- <span>Screenshot</span>
415
- <CommandShortcut>{{ isMac ? '⌘' : 'ALT+' }}S</CommandShortcut>
416
- </CommandItem>
417
380
  <CommandItem
418
381
  value="HTML"
419
382
  @select="copyHtml"
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import { PanelRightOpen } from 'lucide-vue-next'
3
+ import { useSidebar } from '@/components/ui/sidebar'
4
+
5
+ const { setOpenMobile } = useSidebar()
6
+ </script>
7
+
8
+ <template>
9
+ <button class="md:hidden text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" @click="setOpenMobile(false)">
10
+ <PanelRightOpen class="size-4" :stroke-width="1" />
11
+ </button>
12
+ </template>
@@ -80,6 +80,7 @@ provideCommandContext({
80
80
  <ListboxRoot
81
81
  data-slot="command"
82
82
  v-bind="forwarded"
83
+ highlight-on-hover
83
84
  :class="cn('bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md', props.class)"
84
85
  >
85
86
  <slot />
@@ -24,7 +24,7 @@ const modelValue = useVModel(props, "modelValue", emits, {
24
24
  v-model="modelValue"
25
25
  data-slot="input"
26
26
  :class="cn(
27
- 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
27
+ 'file:text-foreground placeholder:text-gray-400 dark:placeholder:text-gray-500 selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
28
28
  'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
29
29
  'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
30
30
  props.class,
@@ -21,7 +21,7 @@ const { isMobile, open, toggleSidebar } = useSidebar()
21
21
  :class="cn('h-7 w-7 hover:bg-transparent', props.class)"
22
22
  @click="toggleSidebar"
23
23
  >
24
- <svg v-if="isMobile" class="size-4 dark:text-gray-400" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round"><line x1="3" y1="7" x2="21" y2="7" /><line x1="3" y1="12" x2="15" y2="12" /><line x1="3" y1="17" x2="18" y2="17" /></svg>
24
+ <PanelRightClose v-if="isMobile" class="size-4 dark:text-gray-400" :stroke-width="1" />
25
25
  <PanelRightOpen v-else-if="open" class="dark:text-gray-400" :stroke-width="1" />
26
26
  <PanelRightClose v-else class="dark:text-gray-400" :stroke-width="1" />
27
27
  <span class="sr-only">Toggle Sidebar</span>
@@ -13,5 +13,5 @@ const forwardedProps = useForwardProps(delegatedProps)
13
13
  </script>
14
14
 
15
15
  <template>
16
- <TagsInputInput v-bind="forwardedProps" :class="cn('text-sm min-h-5 focus:outline-none flex-1 bg-transparent px-1', props.class)" />
16
+ <TagsInputInput v-bind="forwardedProps" :class="cn('text-sm min-h-5 focus:outline-none flex-1 bg-transparent px-1 placeholder:text-gray-400 dark:placeholder:text-gray-500', props.class)" />
17
17
  </template>