@maizzle/framework 6.0.0-rc.11 → 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.
- package/dist/build.mjs +4 -1
- package/dist/build.mjs.map +1 -1
- package/dist/serve.d.mts.map +1 -1
- package/dist/serve.mjs +23 -11
- package/dist/serve.mjs.map +1 -1
- package/dist/server/compatibility.d.mts +54 -2
- package/dist/server/compatibility.d.mts.map +1 -1
- package/dist/server/compatibility.mjs +890 -76
- package/dist/server/compatibility.mjs.map +1 -1
- package/dist/server/linter.d.mts +15 -2
- package/dist/server/linter.d.mts.map +1 -1
- package/dist/server/linter.mjs +194 -43
- package/dist/server/linter.mjs.map +1 -1
- package/dist/server/sfc-utils.d.mts +18 -0
- package/dist/server/sfc-utils.d.mts.map +1 -0
- package/dist/server/sfc-utils.mjs +184 -0
- package/dist/server/sfc-utils.mjs.map +1 -0
- package/dist/server/ui/App.vue +4 -41
- package/dist/server/ui/components/SidebarClose.vue +12 -0
- package/dist/server/ui/components/ui/command/Command.vue +1 -0
- package/dist/server/ui/components/ui/input/Input.vue +1 -1
- package/dist/server/ui/components/ui/sidebar/SidebarTrigger.vue +1 -1
- package/dist/server/ui/components/ui/tags-input/TagsInputInput.vue +1 -1
- package/dist/server/ui/pages/Preview.vue +194 -151
- package/dist/transformers/addAttributes.mjs +10 -6
- package/dist/transformers/addAttributes.mjs.map +1 -1
- package/dist/transformers/inlineCSS.mjs +2 -2
- package/dist/transformers/inlineCSS.mjs.map +1 -1
- package/dist/transformers/purgeCSS.mjs +1 -1
- package/dist/transformers/purgeCSS.mjs.map +1 -1
- package/dist/transformers/tailwindcss.mjs +2 -4
- package/dist/transformers/tailwindcss.mjs.map +1 -1
- package/dist/types/config.d.mts +42 -2
- package/dist/types/config.d.mts.map +1 -1
- package/dist/types/index.d.mts +2 -2
- package/package.json +1 -3
- package/dist/_virtual/_rolldown/runtime.mjs +0 -32
- package/dist/node_modules/picomatch/index.mjs +0 -13
- package/dist/node_modules/picomatch/index.mjs.map +0 -1
- package/dist/node_modules/picomatch/lib/constants.mjs +0 -174
- package/dist/node_modules/picomatch/lib/constants.mjs.map +0 -1
- package/dist/node_modules/picomatch/lib/parse.mjs +0 -1067
- package/dist/node_modules/picomatch/lib/parse.mjs.map +0 -1
- package/dist/node_modules/picomatch/lib/picomatch.mjs +0 -304
- package/dist/node_modules/picomatch/lib/picomatch.mjs.map +0 -1
- package/dist/node_modules/picomatch/lib/scan.mjs +0 -296
- package/dist/node_modules/picomatch/lib/scan.mjs.map +0 -1
- package/dist/node_modules/picomatch/lib/utils.mjs +0 -53
- 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"}
|
package/dist/server/ui/App.vue
CHANGED
|
@@ -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,
|
|
5
|
-
import
|
|
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>
|
|
@@ -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-
|
|
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
|
-
<
|
|
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>
|