Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#31 Bug/fix exit icon #32

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function run() {
let template;

if (existsSync(configPath)) {
const data = fs.readFileSync(configPath);
const data = readFileSync(configPath);
const config = JSON.parse(data);
if (config.defaultModel) {
model = config.defaultModel;
Expand All @@ -79,26 +79,30 @@ async function run() {
]);
model = answer.model;
}

await fileSelector({
message: "Select the file containing the react compontent:",
message: "Select the files containing the React components:",
basePath,
}).then(async (file) => {
if (!file) return;
const input = readFileSync(file, "utf-8");
const extension = path.extname(file);
const spinner = showLoading("Generating story...");
try {
const story = await componentConverter(input.replace(/^\s*[\r\n]/gm, "").trim(), model, template).then(
(story) => {
story = beautify(story, resetOptions);
return beautify(story, options);
}
);
writeFileSync(file.replace(extension, `.story${extension}`), story);
spinner.stopLoading("Story generated!", "\x1b[32m");
} catch (error) {
spinner.stopLoading("Error generating story: " + error.message, "\x1b[91m");
}
}).then(async (selectedFiles) => { // Adjusted to expect an array of selected files
if (!selectedFiles || selectedFiles.length === 0) return; // Check if any files are selected

selectedFiles.forEach(async (file) => { // Loop through selected files
const input = readFileSync(file, "utf-8");
const extension = path.extname(file);
const spinner = showLoading("Generating story...");
try {
const story = await componentConverter(input.replace(/^\s*[\r\n]/gm, "").trim(), model, template).then(
(story) => {
story = beautify(story, resetOptions);
return beautify(story, options);
}
);
writeFileSync(file.replace(extension, `.story${extension}`), story);
spinner.stopLoading(`Story generated for ${file}!`, "\x1b[32m");
} catch (error) {
spinner.stopLoading(`Error generating story for ${file}: ` + error.message, "\x1b[91m");
}
});
});
}

Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 26 additions & 19 deletions src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,31 @@ export async function componentConverter(component, model, template) {
`import type { Meta, StoryObj } from '@storybook/react';\n/* import component file */\nconst meta = {\n title: /* Component title */,\n component: /* Component name */,\n parameters: {\n layout: 'centered'\n },\n tags: ['autodocs'],\n} satisfies Meta<typeof /* Component name */>\n\nexport default meta\n\ntype Story = StoryObj<typeof meta>\n\nexport const /* StoryName */ : Story = {\n args: {\n /* args */\n },\n}`;
const prompt = `You are a senior web developer. You are specialized in creating Storybook stories for React components. Your focus is on aiding expert frontend developers by generating clean, readable, and standardized story code. You strictly adhere to CSF3 conventions and do not use Component Story Format 2 (CSF2).\nThe user will give you the react component and you will reply with the code and nothing else, avoiding comments.\nBelow, here's the template you will stick to. Keep the provided format and add component variants if possible:\n${defaultTemplate}`;

const response = await getClient().chat.completions.create({
model,
messages: [
{
role: "system",
content: prompt,
},
{
role: "user",
content: component,
},
],
max_tokens: 2048,
temperature: 0.5,
top_p: 1.0,
frequency_penalty: 0.5,
presence_penalty: 0.1,
});
const convertedComponents = [];
for (const component of components) {
const response = await getClient().chat.completions.create({
model,
messages: [
{
role: "system",
content: prompt,
},
{
role: "user",
content: component,
},
],
max_tokens: 2048,
temperature: 0.5,
top_p: 1.0,
frequency_penalty: 0.5,
presence_penalty: 0.1,
});

return response.choices[0].message.content;
convertedComponents.push(response.choices[0].message.content);
}



return convertedComponents;
}
55 changes: 38 additions & 17 deletions src/selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export const fileSelector = createPrompt((config, done) => {
const [cursorPosition, setCursorPos] = useState(1);
const [filePath, setFilePath] = useState(basePath);
const [status, setStatus] = useState("pending");

const [selectedFiles, setSelectedFiles] = useState([]);

// Retrieve files and directories
let files = fs
.readdirSync(filePath)
.reduce((acc, file) => {
Expand Down Expand Up @@ -50,12 +52,15 @@ export const fileSelector = createPrompt((config, done) => {
return 0;
});

const goBackOption = { name: `\x1b[90m[..] BACK\x1b[0m`, value: "..", isDirectory: false };
const exitOption = { name: `\x1b[91mⓧ EXIT\x1b[0m`, value: null, isDirectory: false };
// Add navigation options
const goBackOption = { name: `\x1b[90m[..] BACK\x1b[0m`, value: "..", isDirectory: false};
const exitOption = { name: `\x1b[91mX EXIT\x1b[0m`, value: null, isDirectory: false };
const submitOption = { name: `\x1b[92m✔ SUBMIT SELECTED FILES\x1b[0m`, value: "submit", isDirectory: false };

files.unshift(new Separator());
if (filePath !== "./") files.unshift(goBackOption);
if (filePath !== "./") files.unshift(goBackOption); // Show the back option if not in root
files.push(new Separator());
files.push(submitOption); // Add Submit option above Exit
files.push(exitOption);

const choice = files[cursorPosition];
Expand All @@ -64,32 +69,46 @@ export const fileSelector = createPrompt((config, done) => {
if (isEnterKey(key)) {
const selectedOption = files[cursorPosition];

if (selectedOption.value === "..") {
const parentDirectory = path.dirname(filePath);
setFilePath(parentDirectory + "/");
setCursorPos(1);
if (selectedOption.isDirectory) {
// Navigate into directory
if (selectedOption.value === "..") {
const parentDirectory = path.dirname(filePath);
setFilePath(parentDirectory + "/");
} else {
setFilePath(selectedOption.value); // Go into selected directory
}
setCursorPos(0); // Reset cursor when entering new directory
} else if (selectedOption.value === null) {
// Exit option
setStatus("exit");
done(null);
} else if (selectedOption.isDirectory) {
setFilePath(selectedOption.value);
setCursorPos(2);
} else if (selectedOption.value === "submit") {
// Handle file submission
setStatus("done"); // Change status to done
done(selectedFiles); // Call done with selected files
} else {
setStatus("done");
done(`./${selectedOption.value}`);
// Select or deselect file
if (selectedFiles.includes(selectedOption.value)) {
setSelectedFiles(selectedFiles.filter(file => file !== selectedOption.value));
} else {
setSelectedFiles([...selectedFiles, selectedOption.value]);
}
}
} else if (isUpKey(key) || isDownKey(key)) {
// Handle navigation through file list
let newCursorPosition = cursorPosition;
const offset = isUpKey(key) ? -1 : 1;
let selectedOption;

// Ensure the new option is selectable
while (!isSelectableChoice(selectedOption)) {
newCursorPosition = (newCursorPosition + offset + files.length) % files.length;
selectedOption = files[newCursorPosition];
}

setCursorPos(newCursorPosition);
} else if (isNumberKey(key)) {
// Allow quick selection via number keys
const newCursorPosition = Number(key.name) - 1;

if (!isSelectableChoice(files[newCursorPosition])) {
Expand All @@ -101,7 +120,7 @@ export const fileSelector = createPrompt((config, done) => {
});

if (status === "done") {
return `\x1b[92m\x1b[1m✔ Selected file: ${choice.name || choice.value}\x1b[0m`;
return `\x1b[92m\x1b[1m✔ Selected files: ${selectedFiles.join(", ")}\x1b[0m`;
}
if (status === "exit") {
return `\x1b[91m\x1b[1m✘ File selection canceled.\x1b[0m`;
Expand All @@ -113,18 +132,20 @@ export const fileSelector = createPrompt((config, done) => {
}

const line = choice.name || choice.value;
const isSelected = selectedFiles.includes(choice.value);
const selectedMarker = isSelected ? "\x1b[92m✔\x1b[0m " : " ";
if (choice.disabled) {
const disabledLabel = typeof choice.disabled === "string" ? choice.disabled : "(disabled)";
return `\x1b[90m- ${line} ${disabledLabel}\x1b[0m`;
}

if (index === cursorPosition) {
return line.split(" ").length === 2
? `\x1b[36m❯ ${line.split(" ")[0]}\x1b[0m \x1b[36m${line.split(" ")[1]}\x1b[0m`
: `\x1b[36m❯ ${line}\x1b[0m`;
? `${selectedMarker}\x1b[36m❯ ${line.split(" ")[0]}\x1b[0m \x1b[36m${line.split(" ")[1]}\x1b[0m`
: `${selectedMarker}\x1b[36m❯ ${line}\x1b[0m`;
}

return ` ${line}`;
return ` ${selectedMarker} ${line}`;
});

const windowedChoices = usePagination({
Expand Down
Loading