1
0
Fork 0

[studio] fix: Various studio fixes

This commit is contained in:
joostdecock 2025-04-26 15:29:25 +02:00 committed by Joost De Cock
parent ab01a3795d
commit 836e1b6c8e
10 changed files with 450 additions and 644 deletions

880
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -98,7 +98,7 @@
"@babel/preset-react": "^7.22.15", "@babel/preset-react": "^7.22.15",
"c8": "^10.1.2", "c8": "^10.1.2",
"eslint-config-next": "^14.0.1", "eslint-config-next": "^14.0.1",
"glob": "^10.3.10", "glob": "^11.0.1",
"rehype-format": "^5.0.0", "rehype-format": "^5.0.0",
"rehype-stringify": "^10.0.1", "rehype-stringify": "^10.0.1",
"tlds": "^1.255.0" "tlds": "^1.255.0"

View file

@ -36,7 +36,7 @@ export default function Home() {
</h2> </h2>
</div> </div>
<div className="tw:flex tw:flex-col tw:gap-8 md:tw:grid md:tw:grid-cols-2 md:tw:gap-4 tw:mt-12 md:tw:mt-20 md:tw:px-4"> <div className="tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:gap-4 tw:mt-12 md:tw:mt-20 md:tw:px-4">
<Card <Card
title="Batteries Included" title="Batteries Included"
icon={<OkIcon className="tw:w-12 tw:h-12 tw:text-success" stroke={4} />} icon={<OkIcon className="tw:w-12 tw:h-12 tw:text-success" stroke={4} />}

View file

@ -1,4 +1,4 @@
{ {
"version": "4.0.0", "id": "plugin-theme",
"name": "plugin-theme" "version": "4.0.0"
} }

View file

@ -1,5 +1,5 @@
{ {
"name": "@freesewing/undefined", "name": "@freesewing/plugin-theme",
"version": "4.0.0", "version": "4.0.0",
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)", "author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
"homepage": "https://freesewing.org/", "homepage": "https://freesewing.org/",

View file

@ -1,12 +1,22 @@
import fs from 'fs' import {
import path from 'path' fs,
cp,
path,
globDir,
copyFolderRecursively,
rm,
root,
templateOut,
writeJsonFile,
} from './fs.mjs'
import prompts from 'prompts' import prompts from 'prompts'
import chalk from 'chalk' import chalk from 'chalk'
import { banner } from './banner.mjs' import { banner } from './banner.mjs'
import mustache from 'mustache'
import { execSync } from 'child_process' import { execSync } from 'child_process'
import languages from '../config/languages.json' assert { type: 'json' } import languages from '../config/languages.json' assert { type: 'json' }
import { getDesigns, getPlugins } from './software.mjs' import { getDesigns, getPlugins } from './software.mjs'
import conf from '../lerna.json' assert { type: 'json' }
const { version } = conf
const designs = await getDesigns() const designs = await getDesigns()
const plugins = await getPlugins() const plugins = await getPlugins()
@ -19,7 +29,6 @@ export const getInput = async () => {
let template = false let template = false
let name = false let name = false
let finalName = false let finalName = false
const cwd = process.cwd()
// while we're not finalized on a name // while we're not finalized on a name
while (finalName === false) { while (finalName === false) {
@ -58,7 +67,7 @@ export const getInput = async () => {
).name ).name
// check whether a folder with that name already exists // check whether a folder with that name already exists
const dest = path.join(cwd, type + 's', type === 'plugin' ? `plugin-${name}` : name) const dest = path.join(root, type + 's', type === 'plugin' ? `plugin-${name}` : name)
try { try {
const dir = await opendir(dest) const dir = await opendir(dest)
dir.close() dir.close()
@ -115,8 +124,9 @@ async function addDesign({ name, template }) {
console.log(valid) console.log(valid)
process.exit() process.exit()
} }
createDesign(name, template) await createDesign(name, template)
execSync('npm run reconfigure') execSync('npm run reconfigure')
execSync('npm install')
console.log(` console.log(`
👉 We've created your design skeleton at ${chalk.green('designs/' + name)} 👉 We've created your design skeleton at ${chalk.green('designs/' + name)}
@ -179,58 +189,39 @@ function validatePluginName(name) {
else return ' 🙈 Please use only [a-z], no spaces, no capitals, no nothing 🤷' else return ' 🙈 Please use only [a-z], no spaces, no capitals, no nothing 🤷'
} }
function createDesign(name) { async function createDesign(name, template) {
const template = ['config', 'templates', 'design'] const src = ['packages', 'studio', 'template', 'designs', `.${template}`]
const design = ['designs', name] const target = ['designs', name]
const description = 'A FreeSewing pattern that needs a description' const Name = name.charAt(0).toUpperCase() + name.slice(1)
const capitalized_name = name.charAt(0).toUpperCase() + name.slice(1)
// Add to designs config file // Copy template folder
designs[name] = { await copyFolderRecursively(src, target)
code: 'Coder name',
description: description, // Template various mustache files
design: 'Designer name', const files = (await globDir(target, '**/*.mustache'))
difficulty: 1, .map((file) => file.split(`designs${path.sep}${name}${path.sep}`).pop().split(path.sep))
lab: true, .map((found) => ({
org: true, from: [...target, ...found],
tags: ['tagname'], to: [...target, ...found.slice(0, -1), found.slice(-1).pop().split('.mustache')[0]],
techniques: ['techname'], }))
for (const file of files) {
await templateOut(file.from, file.to, { name, Name })
await rm(file.from)
} }
//write(['config', 'software', 'designs.json'], JSON.stringify(orderDesigns(designs), null, 2))
// Create folders // Create about.json
mkdir([...design, 'src']) await writeJsonFile([...target, 'about.json'], {
mkdir([...design, 'i18n']) id: name,
mkdir([...design, 'tests']) code: 'Your name here',
design: 'Your name here',
// Create package.json description: 'A FreeSewing pattern that needs a description',
templateOut([...template, 'package.json.mustache'], [...design, 'package.json'], { name: `${Name} Something`,
name, difficulty: 2,
description, tags: [],
techniques: [],
version,
pkg: `@freesewing/${name}`,
}) })
// Create src/index.mjs
templateOut([...template, 'src', 'index.mjs.mustache'], [...design, 'src', 'index.mjs'], {
capitalized_name,
})
// Copy i18n/index.mjs
cp([...template, 'i18n', 'index.mjs'], [...design, 'i18n', 'index.mjs'])
// Create i18n translation files
for (const language of languages)
templateOut([...template, 'i18n', 'en.json'], [...design, 'i18n', `${language}.json`], {
title: capitalized_name,
description,
})
// Create tests file
cp([...template, 'tests', 'shared.test.mjs'], [...design, 'tests', 'shared.test.mjs'])
// Copy source
for (const file of ['box.mjs']) {
cp([...template, 'src', file], [...design, 'src', file])
}
} }
function createPlugin(name) { function createPlugin(name) {
@ -260,49 +251,6 @@ function createPlugin(name) {
}) })
} }
function templateOut(from, to, data) {
try {
fs.writeFileSync(
path.join(process.cwd(), ...to),
mustache.render(fs.readFileSync(path.join(process.cwd(), ...from), 'utf-8'), data)
)
} catch (err) {
console.log(err)
}
return true
}
function write(to, data) {
try {
fs.writeFileSync(path.join(process.cwd(), ...to), data)
} catch (err) {
console.log(err)
}
return true
}
function mkdir(dir) {
try {
fs.mkdirSync(path.join(process.cwd(), ...dir), { recursive: true })
} catch (err) {
console.log(err)
}
return true
}
function cp(from, to) {
try {
fs.copyFileSync(path.join(process.cwd(), ...from), path.join(process.cwd(), ...to))
} catch (err) {
console.log(err)
}
return true
}
function orderDesigns(designs) { function orderDesigns(designs) {
// Ensure designs are listed alphabetically // Ensure designs are listed alphabetically
const newDesigns = {} const newDesigns = {}

View file

@ -4,11 +4,12 @@
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { glob } from 'glob' import { glob } from 'glob'
import mustache from 'mustache'
/** /**
* Re-export these * Re-export these
*/ */
export { fs, path, glob } export { fs, path, glob, mustache }
/** /**
* The monorepo root folder * The monorepo root folder
@ -154,6 +155,26 @@ export async function readJsonFile(
return content return content
} }
/**
* Templates out a file with mustache
*
* @param {array} from - The source template file
* @param {array} to - The destination file
* @param {object] data - Substitutions for the template
*/
export async function templateOut(from, to, data) {
if (!Array.isArray(from)) from = [from]
if (!Array.isArray(to)) to = [to]
try {
const src = await readFile(from)
await writeFile(to, mustache.render(src, data))
} catch (err) {
console.log(err)
}
return true
}
/** /**
* Writes a file to disk * Writes a file to disk
* *

View file

@ -1,5 +1,3 @@
//import path from 'path'
//import fs from 'fs'
import { import {
fs, fs,
cp, cp,
@ -12,7 +10,6 @@ import {
readJsonFile, readJsonFile,
writeJsonFile, writeJsonFile,
} from './fs.mjs' } from './fs.mjs'
//import { glob } from 'glob'
import yaml from 'js-yaml' import yaml from 'js-yaml'
import chalk from 'chalk' import chalk from 'chalk'
import mustache from 'mustache' import mustache from 'mustache'
@ -192,6 +189,8 @@ await writeFile(
}) })
) )
// Step 7: Remove sites/studio/node_modules
// All done // All done
log.write(chalk.green(' All done\n')) log.write(chalk.green(' All done\n'))
process.exit() process.exit()

View file

@ -6,8 +6,13 @@ To add a new design to the FreeSewing monorepo, run the following command
in the root folder of the monorepo: in the root folder of the monorepo:
``` ```
npm run add design npm run add
``` ```
It will prompt you for your design name, and as whether you want to create a **TL;DR: Just follow the prompts**
design from scratch, or start from a block.
This command will prompt you for a choice between adding a new plugin or a new design.
Choose **Add a new FreeSewing Design**.
Next, it will ask you for a design name, and whether you
want to create a design from scratch, or start from a block.

View file

@ -19,18 +19,17 @@
"@docusaurus/faster": "^3.7.0", "@docusaurus/faster": "^3.7.0",
"@docusaurus/preset-classic": "^3.7.0", "@docusaurus/preset-classic": "^3.7.0",
"@mdx-js/react": "^3.0.0", "@mdx-js/react": "^3.0.0",
"@freesewing/collection": "latest", "@freesewing/collection": "file:../../packages/collection",
"@freesewing/config": "latest", "@freesewing/config": "file:../../packages/config",
"@freesewing/core": "latest", "@freesewing/core": "file:../../packages/core",
"@freesewing/i18n": "latest", "@freesewing/i18n": "file:../../packages/i18n",
"@freesewing/react": "latest", "@freesewing/react": "file:../../packages/react",
"@freesewing/snapseries": "latest", "@freesewing/snapseries": "file:../../packages/snapseries",
"@freesewing/utils": "latest", "@freesewing/utils": "file:../../packages/utils",
"@freesewing/plugin-i18n": "latest", "@freesewing/plugin-i18n": "file:../../plugins/plugin-i18n",
"@freesewing/plugin-theme": "latest", "@freesewing/plugin-theme": "file:../../plugins/plugin-theme",
"@freesewing/plugin-timing": "latest", "@freesewing/plugin-timing": "file:../../plugins/plugin-timing",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"lodash": "^4.17.21",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prism-react-renderer": "^2.3.0", "prism-react-renderer": "^2.3.0",
"react": "^19.0.0", "react": "^19.0.0",
@ -45,7 +44,7 @@
"@tailwindcss/postcss": "^4.1.3", "@tailwindcss/postcss": "^4.1.3",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"daisyui": "^5.0.19", "daisyui": "^5.0.19",
"glob": "^11.0.0", "glob": "^11.0.1",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"tailwindcss": "^4.1.3", "tailwindcss": "^4.1.3",