@gallop.software/studio 2.3.159 → 2.3.160

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.
@@ -11,7 +11,7 @@
11
11
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
12
  }
13
13
  </style>
14
- <script type="module" crossorigin src="/assets/index-DTMba9ep.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-Ceh3JCXY.js"></script>
15
15
  <link rel="stylesheet" crossorigin href="/assets/index-DfPQBmNf.css">
16
16
  </head>
17
17
  <body>
@@ -4693,25 +4693,40 @@ async function handleFontsUpload(request) {
4693
4693
  try {
4694
4694
  const formData = await request.formData();
4695
4695
  const file = formData.get("file");
4696
- const targetPath = formData.get("path") || "_fonts";
4696
+ const basePath = formData.get("path") || "_fonts";
4697
4697
  if (!file) {
4698
4698
  return jsonResponse({ error: "No file provided" }, { status: 400 });
4699
4699
  }
4700
4700
  if (!file.name.toLowerCase().endsWith(".ttf")) {
4701
4701
  return jsonResponse({ error: "Only TTF files are supported" }, { status: 400 });
4702
4702
  }
4703
- if (!targetPath.startsWith("_fonts")) {
4703
+ if (!basePath.startsWith("_fonts")) {
4704
4704
  return jsonResponse({ error: "Can only upload to _fonts/" }, { status: 400 });
4705
4705
  }
4706
4706
  const bytes = await file.arrayBuffer();
4707
4707
  const buffer = Buffer.from(bytes);
4708
+ const fileName = file.name.toLowerCase();
4709
+ const dashIndex = fileName.indexOf("-");
4710
+ let folderName;
4711
+ if (dashIndex > 0) {
4712
+ folderName = fileName.substring(0, dashIndex);
4713
+ } else {
4714
+ folderName = fileName.replace(".ttf", "");
4715
+ }
4716
+ let targetPath;
4717
+ if (basePath === "_fonts") {
4718
+ targetPath = `_fonts/${folderName}`;
4719
+ } else {
4720
+ targetPath = basePath;
4721
+ }
4708
4722
  const uploadDir = getWorkspacePath(targetPath);
4709
4723
  await fs12.mkdir(uploadDir, { recursive: true });
4710
- const filePath = path11.join(uploadDir, file.name.toLowerCase());
4724
+ const filePath = path11.join(uploadDir, fileName);
4711
4725
  await fs12.writeFile(filePath, buffer);
4712
4726
  return jsonResponse({
4713
4727
  success: true,
4714
- path: `${targetPath}/${file.name.toLowerCase()}`
4728
+ path: `${targetPath}/${fileName}`,
4729
+ folder: targetPath
4715
4730
  });
4716
4731
  } catch (error) {
4717
4732
  console.error("Error uploading font:", error);
@@ -4776,6 +4791,66 @@ async function handleFontsDelete(request) {
4776
4791
  return jsonResponse({ error: "Failed to delete" }, { status: 500 });
4777
4792
  }
4778
4793
  }
4794
+ async function handleFontsDeleteStream(request) {
4795
+ try {
4796
+ const { paths } = await request.json();
4797
+ if (!paths || !Array.isArray(paths) || paths.length === 0) {
4798
+ return jsonResponse({ error: "Paths are required" }, { status: 400 });
4799
+ }
4800
+ for (const p of paths) {
4801
+ if (!p.startsWith("_fonts/")) {
4802
+ return jsonResponse({ error: `Path not allowed: ${p}` }, { status: 400 });
4803
+ }
4804
+ }
4805
+ const encoder = new TextEncoder();
4806
+ const stream = new ReadableStream({
4807
+ async start(controller) {
4808
+ const send = (data) => {
4809
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
4810
+
4811
+ `));
4812
+ };
4813
+ const deleted = [];
4814
+ const errors = [];
4815
+ for (let i = 0; i < paths.length; i++) {
4816
+ const p = paths[i];
4817
+ const fileName = p.split("/").pop() || p;
4818
+ send({ status: "progress", message: `Deleting ${fileName}...`, current: i + 1, total: paths.length });
4819
+ await new Promise((resolve2) => setTimeout(resolve2, 1e3));
4820
+ try {
4821
+ const fullPath = getWorkspacePath(p);
4822
+ const stat = await fs12.stat(fullPath);
4823
+ if (stat.isDirectory()) {
4824
+ await fs12.rm(fullPath, { recursive: true });
4825
+ } else {
4826
+ await fs12.unlink(fullPath);
4827
+ }
4828
+ deleted.push(p);
4829
+ } catch (err) {
4830
+ errors.push(`Failed to delete ${p}: ${err instanceof Error ? err.message : "Unknown error"}`);
4831
+ }
4832
+ }
4833
+ send({
4834
+ status: "complete",
4835
+ message: `Deleted ${deleted.length} item${deleted.length !== 1 ? "s" : ""}`,
4836
+ deleted,
4837
+ errors: errors.length > 0 ? errors : void 0
4838
+ });
4839
+ controller.close();
4840
+ }
4841
+ });
4842
+ return new Response(stream, {
4843
+ headers: {
4844
+ "Content-Type": "text/event-stream",
4845
+ "Cache-Control": "no-cache",
4846
+ "Connection": "keep-alive"
4847
+ }
4848
+ });
4849
+ } catch (error) {
4850
+ console.error("Error deleting:", error);
4851
+ return jsonResponse({ error: "Failed to delete" }, { status: 500 });
4852
+ }
4853
+ }
4779
4854
  async function handleFontsRename(request) {
4780
4855
  try {
4781
4856
  const { oldPath, newName } = await request.json();
@@ -5232,6 +5307,7 @@ async function startServer(options) {
5232
5307
  app.post("/api/studio/fonts/upload", wrapRawHandler(handleFontsUpload));
5233
5308
  app.post("/api/studio/fonts/create-folder", wrapHandler(handleFontsCreateFolder));
5234
5309
  app.post("/api/studio/fonts/delete", wrapHandler(handleFontsDelete));
5310
+ app.post("/api/studio/fonts/delete-stream", wrapHandler(handleFontsDeleteStream, true));
5235
5311
  app.post("/api/studio/fonts/rename", wrapHandler(handleFontsRename));
5236
5312
  app.post("/api/studio/fonts/rename-stream", wrapHandler(handleFontsRenameStream, true));
5237
5313
  app.post("/api/studio/fonts/scan", wrapHandler(handleFontsScan));